package com.fowo.api.inventory.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.convert.Convert;
import cn.hutool.core.date.DatePattern;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.exceptions.ExceptionUtil;
import cn.hutool.core.map.MapUtil;
import cn.hutool.core.util.*;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Assert;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.conditions.update.LambdaUpdateChainWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.fowo.api.inventory.config.*;
import com.fowo.api.inventory.entity.*;
import com.fowo.api.inventory.mapper.*;
import com.fowo.api.inventory.model.*;
import com.fowo.api.inventory.model.form.InventoryExchangeFormVo;
import com.fowo.api.inventory.model.form.InventoryOutboundFormVo;
import com.fowo.api.inventory.model.form.InventoryStorageBaseVo;
import com.fowo.api.inventory.model.form.InventoryStorageFormVo;
import com.fowo.api.inventory.service.InventoryBusinessService;
import com.fowo.api.inventory.service.InventoryException;
import com.fowo.api.model.nav.sell.order.detail.NavSellOrderDetailItemVo;
import com.fowo.api.model.warehousebinrules.WarehouseBinRulesItemVo;
import com.fowo.api.model.warehousebinrules.WarehouseBinRulesSearchParamPo;
import com.fowo.api.service.impl.WarehouseBinRulesServiceImpl;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.stereotype.Service;
import org.springframework.transaction.TransactionDefinition;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.util.*;
import java.util.stream.Collectors;

@Service
@Slf4j
public class InventoryBusinessServiceImpl extends ServiceImpl<InventoryMapper, Inventory> implements InventoryBusinessService {
    @Resource
    private DataSourceTransactionManager dataSourceTransactionManager;
    @Resource
    private TransactionDefinition transactionDefinition;

    //主库存表
    @Resource
    private InventoryServiceImpl inventoryService;
    // 库存变动表
    @Resource
    private InventoryVariationServiceImpl inventoryVariationService;
    //库存货位放置表
    @Resource
    private InventoryPlacementServiceImpl inventoryPlacementService;
    //余额表表
    @Resource
    private InventoryMonthlyServiceImpl inventoryMonthlyService;
    //批次库存表
    @Resource
    private InventoryBatchNoServiceImpl inventoryBatchNoService;
    //库位变动表
    @Resource
    private InventoryPlacementVariationServiceImpl inventoryPlacementVariationService;


    //主库存表
    @Resource
    private InventoryMapper inventoryMapper;
    // 库存变动表
    @Resource
    private InventoryVariationMapper inventoryVariationMapper;
    //库存货位放置表
    @Resource
    private InventoryPlacementMapper inventoryPlacementMapper;
    //余额表表
    @Resource
    private InventoryMonthlyMapper inventoryMonthlyMapper;
    //批次库存表
    @Resource
    private InventoryBatchNoMapper inventoryBatchNoMapper;
    //库位变动表
    @Resource
    private InventoryPlacementVariationMapper inventoryPlacementVariationMapper;
    //可用库存
    @Resource
    private WarehouseBinRulesServiceImpl warehouseBinRulesService;

    /**
     select *  FROM inventory; #库存总表  维度:仓库,物料
     select *  FROM inventory_variation; #库存流水 单据号字段 或者 维度:仓库,物料(对应库存总表)
     select *  FROM inventory_aux_unit;  #规格(预留)
     select *  FROM inventory_batch_no;  #库龄  维度:仓库,物料  与库存总表区别:1.库存总表:一条总流水 2.库龄:入库插入流水,出库更新流水
     select *  FROM inventory_placement; #仓位表  维度:仓库,物料,仓位
     select *  FROM inventory_placement_variation; 仓位流水表  单据号字段 或者 维度:仓库,物料,仓位
     */


    /**
     * 整单入库
     *
     * @param model 整单入库参数
     * @return
     * @throws Exception
     */
    @Override
    public InventoryListReturnVo storage(InventoryStorageFormVo model) throws Exception {
        Assert.isTrue(ObjUtil.isNotEmpty(model) && CollUtil.isNotEmpty(model.getItems()), "项目不能为空！");
        // 验证参数
        this.prepareInventoryStorage(model);
        // 将表单属性填充到项中
        for (InventoryStorageVo item : model.getItems()) {
            this.fullInventoryStorage(model, item);
            if (BooleanUtil.isTrue(model.getReverseQtySign())) {
                if (MapUtil.isNotEmpty(item.getBinIds())) {
                    for (Long key : item.getBinIds().keySet()) {
                        item.getBinIds().put(key, 0 - MapUtil.getInt(item.getBinIds(), key));
                    }
                }
            }
            item.setStockId(model.getStockId());
            item.setTo(model.getTo());
        }
        InventoryListReturnVo returnVo = new InventoryListReturnVo();
        returnVo.setInventoryStorageVo(model);
        // 开始事务
        TransactionStatus transactionStatus = null;
        try {
            transactionStatus = dataSourceTransactionManager.getTransaction(transactionDefinition);
            List<String> errList = new ArrayList<>();
            for (InventoryStorageVo item : model.getItems()) {
                try {
                    final InventoryListReturnVo inventoryListReturnVo = this.storageItem(item);
                    returnVo.add(inventoryListReturnVo);
                } catch (Exception exx) {
                    log.error("整单入库发生异常,异常信息:" + StrUtil.subPre(ExceptionUtil.getRootCauseMessage(exx), 2000));
                    errList.add(StrUtil.subPre(ExceptionUtil.getRootCauseMessage(exx), 2000));
                }
            }
            Assert.isTrue(CollUtil.isEmpty(errList), StrUtil.join(";", errList));
            // 提交事务
            dataSourceTransactionManager.commit(transactionStatus);
        } catch (Exception ex) {
            if (transactionStatus != null) {
                dataSourceTransactionManager.rollback(transactionStatus);
            }
            throw ex;
        }
        return returnVo;
    }

    /**
     * 整单出库
     *
     * @param model 整单出库参数
     * @return 结果
     */
    @Override
    public InventoryListReturnVo outbound(InventoryOutboundFormVo model) throws Exception {
        Assert.isTrue(ObjUtil.isNotEmpty(model) && CollUtil.isNotEmpty(model.getItems()), "项目不能为空！");
        // 验证参数
        this.prepareInventoryStorage(model);
        // 将表单属性填充到项中
        for (InventoryOutboundVo item : model.getItems()) {
            this.fullInventoryStorage(model, item);
            if (BooleanUtil.isTrue(model.getReverseQtySign())) {
                if (MapUtil.isNotEmpty(item.getBinIds())) {
                    for (Long key : item.getBinIds().keySet()) {
                        item.getBinIds().put(key, 0 - MapUtil.getInt(item.getBinIds(), key));
                    }
                }
            }
            item.setStockId(model.getStockId());
            item.setModel(model.getModel());
            item.setFrom(model.getFrom());
        }
        InventoryListReturnVo returnVo = new InventoryListReturnVo();
        returnVo.setInventoryStorageVo(model);
        TransactionStatus transactionStatus = null;
        try {
            transactionStatus = dataSourceTransactionManager.getTransaction(transactionDefinition);
            List<String> errList = new ArrayList<>();
            for (InventoryOutboundVo item : model.getItems()) {
                try {
                    final InventoryListReturnVo inventoryListReturnVo = this.outboundItem(item);
                    returnVo.add(inventoryListReturnVo);
                } catch (Exception exx) {
                    log.error("整单入库发生异常,异常信息:" + StrUtil.subPre(ExceptionUtil.getRootCauseMessage(exx), 2000));
                    errList.add(StrUtil.subPre(ExceptionUtil.getRootCauseMessage(exx), 2000));
                }
            }
            Assert.isTrue(CollUtil.isEmpty(errList), StrUtil.join(";", errList));
            dataSourceTransactionManager.commit(transactionStatus);
        } catch (Exception ex) {
            if (transactionStatus != null) {
                dataSourceTransactionManager.rollback(transactionStatus);
            }
            throw ex;
        }
        return returnVo;
    }

    /**
     * 整单库存内流转
     *
     * @param model 整单库存内流转参数模型
     * @return 操作结果
     */
    @Override
    public synchronized InventoryListReturnVo exchange(InventoryExchangeFormVo model) throws Exception {
        Assert.isTrue(ObjUtil.isNotEmpty(model) && CollUtil.isNotEmpty(model.getItems()), "项目不能为空！");
        // 验证参数
        this.prepareInventoryStorage(model);
        // 将表单属性填充到项中
        for (InventoryExchangeVo item : model.getItems()) {
            this.fullInventoryStorage(model, item);
            if (BooleanUtil.isTrue(model.getReverseQtySign())) {
                if (MapUtil.isNotEmpty(item.getToBinIds())) {
                    for (Long key : item.getToBinIds().keySet()) {
                        item.getToBinIds().put(key, 0 - MapUtil.getInt(item.getToBinIds(), key));
                    }
                }
                if (MapUtil.isNotEmpty(item.getFromBinIds())) {
                    for (Long key : item.getFromBinIds().keySet()) {
                        item.getFromBinIds().put(key, 0 - MapUtil.getInt(item.getFromBinIds(), key));
                    }
                }
            }
            item.setFromStockId(model.getFromStockId());
            item.setToStockId(model.getToStockId());
            item.setFromStockId(model.getFromStockId());
            item.setFrom(model.getFrom());
            item.setTo(model.getTo());
            item.setModel(model.getModel());
        }
        InventoryListReturnVo returnVo = new InventoryListReturnVo();
        returnVo.setInventoryStorageVo(model);
        // 开始事务
        TransactionStatus transactionStatus = null;
        try {
            transactionStatus = dataSourceTransactionManager.getTransaction(transactionDefinition);
            List<String> errList = new ArrayList<>();
            for (InventoryExchangeVo item : model.getItems()) {
                try {
                    final InventoryListReturnVo inventoryListReturnVo = exchangeItem(item);
                    returnVo.add(inventoryListReturnVo);
                } catch (Exception exx) {
                    log.error("整单入库发生异常,异常信息:" + StrUtil.subPre(ExceptionUtil.getRootCauseMessage(exx), 2000));
                    errList.add(StrUtil.subPre(ExceptionUtil.getRootCauseMessage(exx), 2000));
                }
            }
            Assert.isTrue(CollUtil.isEmpty(errList), StrUtil.join(";", errList));
            dataSourceTransactionManager.commit(transactionStatus);
        } catch (Exception ex) {
            if (transactionStatus != null) {
                dataSourceTransactionManager.rollback(transactionStatus);
            }
            throw ex;
        }
        return returnVo;
    }

    /**
     * 验证参数
     *
     * @param model
     * @throws Exception
     */
    protected void prepareInventoryStorage(InventoryStorageBaseVo model) throws Exception {
        if (StringUtils.isEmpty(model.getOperateKey())) {
            // 使用雪花算法生成操作统一键
            model.setOperateKey(IdUtil.getSnowflakeNextIdStr());
        }
        if (ObjectUtils.isNotEmpty(model.getOrderDate())) {
            //如果单据时间小于结账日期 不予操作
            if (StringUtils.isNotEmpty(CarryDateConfig.sql)) {
                Date date = inventoryMapper.selectCarryDate(CarryDateConfig.sql);
                Assert.isTrue(ObjUtil.isNotEmpty(date) && model.getOrderDate().getTime() > date.getTime(), "单据日期小于结账日期,请检查!");
            }
        }
    }

    /**
     * 将表单属性填充到项中
     *
     * @param model
     * @param item
     */
    private void fullInventoryStorage(InventoryStorageBaseVo model, BaseInventoryItemVo item) {
        if (BooleanUtil.isTrue(model.getReverseQtySign())) {
            item.setQty(item.getQty().negate());
        }

        item.setDocumentType(model.getDocumentType());
        item.setSupportNegative(model.getSupportNegative());

        item.setOperate(model.getOperate());
        item.setFormNum(model.getFormNum());
        item.setFormOperator(model.getFormOperator());
        item.setOperateKey(model.getOperateKey());
        //如果启用批次号 放入唯一批次号
        if (Convert.toBool(model.getBatchManagement(), true)) {
            final String batchNo = createBatchNo();
            item.setBatchNo(batchNo);
            model.setBatchNo(batchNo);
        }
        if (ObjUtil.isEmpty(item.getUserData1())) {
            item.setUserData1(model.getUserData1());
        }
        if (ObjUtil.isEmpty(item.getUserData2())) {
            item.setUserData2(model.getUserData2());
        }
        if (ObjUtil.isEmpty(item.getUserData3())) {
            item.setUserData3(model.getUserData3());
        }
        if (ObjUtil.isEmpty(item.getUserData4())) {
            item.setUserData4(model.getUserData4());
        }
        if (ObjUtil.isEmpty(item.getUserData5())) {
            item.setUserData5(model.getUserData5());
        }
        if (ObjUtil.isEmpty(item.getUserData6())) {
            item.setUserData6(model.getUserData6());
        }
        if (ObjUtil.isEmpty(item.getUserData7())) {
            item.setUserData7(model.getUserData7());
        }
        if (ObjUtil.isEmpty(item.getUserData8())) {
            item.setUserData8(model.getUserData8());
        }
        if (ObjUtil.isEmpty(item.getRemark())) {
            item.setRemark(model.getRemark());
        }
    }


    @Override
    public void updateMonthly(UpdateMonthlyVo model) throws Exception {
        List<Inventory> list = this.list(new QueryWrapper<Inventory>().lambda().eq(ObjUtil.isNotEmpty(model.getStockId()), Inventory::getStockId, model.getStockId()));
        List<InventoryMonthly> inventoryMonthlyList = list.stream().map(m -> {
            InventoryMonthly inventoryMonthly = BeanUtil.copyProperties(m, InventoryMonthly.class);
            inventoryMonthly.setPeriodId(model.getPeriodId());
            return inventoryMonthly;
        }).collect(Collectors.toList());
        inventoryMonthlyService.saveBatch(inventoryMonthlyList);
    }


    /**
     * 单次库存内流转
     *
     * @param model
     * @return
     */
    @Transactional(rollbackFor = Exception.class)
    @Override
    public synchronized InventoryListReturnVo exchangeItem(InventoryExchangeVo model) throws Exception {
        getDocumentType(model.getDocumentType());
        verificationExchange(model);
        List<BinIdsVo> fromBinIdsVos = new ArrayList<>();
        if (model.getQty().compareTo(BigDecimal.ZERO) == 0) {
            return new InventoryListReturnVo();
        }
        if (null != model.getFromBinIds()) {
            fromBinIdsVos = model.getFromBinIds().entrySet().stream().map(c -> new BinIdsVo(c.getKey(), c.getValue())).collect(Collectors.toList());
            long sum = fromBinIdsVos.stream().mapToLong(BinIdsVo::getQty).sum();
            if (QtyIsZeroConfig.isOpen) {
                if (model.getQty().compareTo(BigDecimal.ZERO) == 0) {
                    return new InventoryListReturnVo();
                }
                if (model.getQty().longValue() != sum) {
                    throw new Exception("fromBindIds 为非空时，所有入位数量合计不等于qty");
                }
            } else if (sum <= 0 || model.getQty().longValue() != sum) {
                throw new Exception("fromBindIds 为非空时，所有入位数量大于0并且合计不等于qty");
            }
        }
        List<BinIdsVo> toBinIdsVos = new ArrayList<>();
        if (null != model.getFromBinIds()) {
            toBinIdsVos = model.getToBinIds().entrySet().stream().map(c -> new BinIdsVo(c.getKey(), c.getValue())).collect(Collectors.toList());
            long sum = toBinIdsVos.stream().mapToLong(BinIdsVo::getQty).sum();
            if (QtyIsZeroConfig.isOpen) {
                if (model.getQty().compareTo(BigDecimal.ZERO) == 0) {
                    return new InventoryListReturnVo();
                }
                if (model.getQty().longValue() != sum) {
                    throw new Exception("toBindIds 为非空时，所有入位数量合计不等于qty");
                }
            } else if (sum <= 0 || model.getQty().longValue() != sum) {
                throw new Exception("toBindIds 为非空时，所有入位数量大于0并且合计不等于qty");
            }
        }


/**
 仓库: 1          1         1          2
 仓位: A    ->    A    ->   B    ->    C
 仓位流转     仓库流转    跨库调拨
 库存流水     库存流水    库存流水
 */
//        仓库内移货位
//        条件为： fromStockId == toStockId && from == to && fromBinIds != null && toBinIds != null
//        按给出的业务唯一标识，选择模式，fromBinIds 选择满足条件的from库存记录
//        按给出的业务唯一标识，选择模式，toBinIds 选择满足条件的to库存记录
//        减少 from 的库存数，添加到对应 to 的库存数中，如果对应 to 库存记录不存在就新增


        if (model.getFromStockId().equals(model.getToStockId())) {
            //仓位流转
            if (model.getFrom().equals(model.getTo()) && model.getFromBinIds() != null && model.getToBinIds() != null) {
                if (StockAgeConfig.isOpen) {
                    //库位操作  不用使用
                    //exchangeShiftBatchNo(model, fromBinIdsVos, toBinIdsVos);
                }
                return exchangeShift(model, fromBinIdsVos, toBinIdsVos);

            }
            //仓库流转
            else if (!model.getFrom().equals(model.getTo())) {
                if (StockAgeConfig.isOpen) {
                    // 批次库存数量转换
                    exchangeTargetTypeBatchNo(model);
                }
                return exchangeTargetType(model);
            }
        }
//        跨库调拨
//        条件为 fromStockId != toStockId
//        此情况 exchange 自动完成分别调用出仓的 outbound 和入仓的 storage，对应变更的 operate（操作名称）自动配置为 “调拨出库”与“调拨入库”
        if (!model.getFromStockId().equals(model.getToStockId())) {
            //通过配置 是做库存还是批次库存不用改
            return exchangeAllot(model);
//            if(StockAgeConfig.isOpen){
//
//            }else {
//
//            }

        }
        return null;
    }

    private InventoryListReturnVo exchangeTargetTypeBatchNo(InventoryExchangeVo model) throws Exception {
        if (model.getFromBinIds() != null || model.getToBinIds() != null) {
            throw new Exception("此操作目前不支持带库位处理!");
        }
        boolean IsOpenNegativeInventory = getIsOpenNegativeInventory(model.getFromStockId());
        List<InventoryBatchNo> inventoryBatchNoList = inventoryBatchNoMapper.selectList(queryWrapperInventoryexchangeSqlBatchNo(model));
        if (CollectionUtils.isEmpty(inventoryBatchNoList)) {
            if (IsOpenNegativeInventory) {
                throw new Exception(getItemIdName(model.getItem().getId()) + "要操作的源库存不存在！");
            } else {
                //添加新的 在处理
                InventoryStorageVo inventoryStorageVo = new InventoryStorageVo();
                BeanUtils.copyProperties(model, inventoryStorageVo);
                inventoryStorageVo.setQty(BigDecimal.valueOf(0));
                inventoryStorageVo.setTo(model.getFrom());
                inventoryStorageVo.setStockId(model.getFromStockId());
                InventoryListReturnVo inventoryListReturnVo = new InventoryListReturnVo();
                storageAgeInsert(inventoryStorageVo, inventoryListReturnVo, null);
                inventoryBatchNoList = inventoryBatchNoMapper.selectList(queryWrapperInventoryexchangeSqlBatchNo(model));
            }

        }
        if (IsOpenNegativeInventory) {
            verificationOexchangeTargetTypeBatchNo(model, inventoryBatchNoList);
        }
        BigDecimal qtySum = model.getQty();

        //InventoryBatchNo inventory =inventoryBatchNoList.get(0);
        InventoryListReturnVo inventoryListReturnVo = new InventoryListReturnVo();
        for (InventoryBatchNo inventory : inventoryBatchNoList) {
            //需要处理的数量
            BigDecimal num = model.getQty();
            if (qtySum.compareTo(BigDecimal.ZERO) == 0) {
                //库存都处理完
                break;
            }
            ChangeNum stockQty = new ChangeNum(inventory.getStockQty());
            ChangeNum lockQty = new ChangeNum(inventory.getLockQty());
            ChangeNum displayQty = new ChangeNum(inventory.getDisplayQty());
            ChangeNum defectQty = new ChangeNum(inventory.getDefectQty());
            ChangeNum wayQty = new ChangeNum(inventory.getWayQty());
            ChangeNum storageQty = new ChangeNum(inventory.getStorageQty());
            ChangeNum rejectLockQty = new ChangeNum(inventory.getRejectLockQty());
            ChangeNum rejectWayQty = new ChangeNum(inventory.getRejectWayQty());
            ChangeNum inspectedQty = new ChangeNum(inventory.getInspectedQty());
            ChangeNum pickingQty = new ChangeNum(inventory.getPickingQty());
//            BigDecimal normalQty = stockQty.subtract(lockQty.getValue()).subtract(defectQty.getValue()).subtract(displayQty.getValue());
            BigDecimal normalQty = NumberUtil.sub(stockQty.getValue(), lockQty.getValue(), defectQty.getValue(), displayQty.getValue());
            InventoryVariation inventoryVariation = new InventoryVariation();
            BeanUtils.copyProperties(model, inventoryVariation);
            inventoryVariation.setChangeType("Exchange");
            inventoryVariation.setStockId(model.getFromStockId());
            inventoryVariation.setFromType(model.getFrom().getValue());
            inventoryVariation.setToType(model.getTo().getValue());
            inventoryVariation.setItemId(model.getItem().getId());
            inventoryVariation.setOperateTime(new Date());

            InventoryBatchNo updateInventory = new InventoryBatchNo();

            // 处理出
            switch (model.getFrom().getValue()) {
                case TargetTypeVo.Normal:
                    if (!IsOpenNegativeInventory) {
                        stockQty.subtract(model.getQty());
                        qtySum = BigDecimal.ZERO;
                    } else if (stockQty.getValue().compareTo(qtySum) >= 0) {
                        num = qtySum;
                        stockQty.subtract(qtySum);
                        qtySum = BigDecimal.ZERO;
                    } else {
                        num = stockQty.getValue();
                        qtySum = qtySum.subtract(stockQty.getValue());
                        stockQty.subtract(stockQty.getValue());

                    }
                    // stockQty.subtract(model.getQty());
                    break;
                case TargetTypeVo.Display:
                    if (!IsOpenNegativeInventory) {
                        stockQty.subtract(model.getQty());
                        displayQty.subtract(model.getQty());
                        qtySum = BigDecimal.ZERO;
                    } else if (displayQty.getValue().compareTo(qtySum) >= 0) {
                        num = qtySum;
                        stockQty.subtract(qtySum);
                        displayQty.subtract(qtySum);
                        qtySum = BigDecimal.ZERO;
                    } else {
                        num = displayQty.getValue();
                        qtySum = qtySum.subtract(stockQty.getValue());
                        stockQty.subtract(stockQty.getValue());
                        displayQty.subtract(displayQty.getValue());
                    }

                    // stockQty.subtract(model.getQty());
                    // displayQty.subtract(model.getQty());
                    break;
                case TargetTypeVo.Defect:
                    if (!IsOpenNegativeInventory) {
                        stockQty.subtract(model.getQty());
                        defectQty.subtract(model.getQty());
                        qtySum = BigDecimal.ZERO;
                    } else if (defectQty.getValue().compareTo(qtySum) >= 0) {
                        num = qtySum;
                        stockQty.subtract(qtySum);
                        defectQty.subtract(qtySum);
                        qtySum = BigDecimal.ZERO;
                    } else {
                        num = defectQty.getValue();
                        qtySum = qtySum.subtract(stockQty.getValue());
                        stockQty.subtract(stockQty.getValue());
                        defectQty.subtract(defectQty.getValue());

                    }
                    //stockQty.subtract(model.getQty());
                    //defectQty.subtract(model.getQty());
                    break;
                case TargetTypeVo.Lock:
                    if (!IsOpenNegativeInventory) {
                        stockQty.subtract(model.getQty());
                        lockQty.subtract(model.getQty());
                        qtySum = BigDecimal.ZERO;
                    } else if (lockQty.getValue().compareTo(qtySum) >= 0) {
                        num = qtySum;
                        stockQty.subtract(qtySum);
                        lockQty.subtract(qtySum);
                        qtySum = BigDecimal.ZERO;
                    } else {
                        num = lockQty.getValue();
                        qtySum = qtySum.subtract(stockQty.getValue());
                        stockQty.subtract(stockQty.getValue());
                        lockQty.subtract(lockQty.getValue());

                    }
                    //stockQty.subtract(model.getQty());
                    //lockQty.subtract(model.getQty());
                    break;
                case TargetTypeVo.Way:
                    if (!IsOpenNegativeInventory) {
                        wayQty.subtract(model.getQty());
                        qtySum = BigDecimal.ZERO;
                    } else if (wayQty.getValue().compareTo(qtySum) >= 0) {
                        num = qtySum;
                        wayQty.subtract(qtySum);
                        qtySum = BigDecimal.ZERO;
                    } else {
                        num = wayQty.getValue();
                        qtySum = qtySum.subtract(wayQty.getValue());
                        wayQty.subtract(wayQty.getValue());

                    }
                    //wayQty.subtract(model.getQty());
                    break;
                case TargetTypeVo.Storage:
//                    if (!IsOpenNegativeInventory) {
//                        storageQty.subtract(model.getQty());
//                        qtySum = BigDecimal.ZERO;
//                    } else if (storageQty.getValue().compareTo(qtySum) >= 0) {
//                        num = qtySum;
//                        storageQty.subtract(qtySum);
//                        qtySum = BigDecimal.ZERO;
//                    } else {
//                        num = storageQty.getValue();
//                        qtySum = qtySum.subtract(storageQty.getValue());
//                        storageQty.subtract(storageQty.getValue());
//                    }

                    if (!IsOpenNegativeInventory || storageQty.getValue().compareTo(qtySum) >= 0) { //开启负库存 || 暂存数量够
                        num = qtySum;
                        storageQty.subtract(qtySum);
                        qtySum = BigDecimal.ZERO;
                    } else if (NumberUtil.isGreater(NumberUtil.add(normalQty, storageQty.getValue()), qtySum)) {  //暂存 + 可用够
                        num = qtySum;
                        final BigDecimal storageQtyBase = storageQty.getValue();
                        storageQty.subtract(storageQtyBase);
                        stockQty.subtract(qtySum.subtract(storageQtyBase));
                        qtySum = BigDecimal.ZERO;
                    } else {  //暂存 + 可用不够:扣完
                        num = NumberUtil.add(normalQty, storageQty.getValue());
                        storageQty.subtract(storageQty.getValue());
                        stockQty.subtract(normalQty);
                        qtySum = qtySum.subtract(num);
                    }


//                    if (!getIsOpenNegativeInventory(model.getStockId()) || storageQty.compareTo(qtySum) >= 0) { //开启负库存 || 暂存数量够
//                        updateInventory.setStorageQty(storageQty.subtract(qtySum));
//                        inventoryVariation.setStorageQty(updateInventory.getStorageQty());
//                        inventoryVariation.setChangeStorageQty(qtySum.negate());
//                        qtySum = BigDecimal.ZERO;
//                    } else if (NumberUtil.isGreater(NumberUtil.add(normalQty, storageQty), qtySum)) {   //暂存 + 可用够
//                        updateInventory.setStorageQty(BigDecimal.ZERO);
//                        updateInventory.setStockQty(stockQty.subtract(qtySum.subtract(storageQty))); //剩余可用(锁定 + 陈列 + 残次) = 总可用 - 可用
//                        inventoryVariation.setStorageQty(BigDecimal.ZERO);
//                        inventoryVariation.setStockQty(stockQty.subtract(qtySum.subtract(storageQty)));
//                        inventoryVariation.setChangeStorageQty(storageQty.negate());
//                        inventoryVariation.setChangeStockQty(qtySum.subtract(storageQty).negate());
//                        qtySum = BigDecimal.ZERO;
//                    } else {   //暂存 + 可用不够:扣完
//                        updateInventory.setStorageQty(BigDecimal.ZERO);
//                        updateInventory.setStockQty(NumberUtil.sub(stockQty, normalQty)); //剩余可用(锁定 + 陈列 + 残次) = 总可用 - 可用
//                        inventoryVariation.setStorageQty(BigDecimal.ZERO);
//                        inventoryVariation.setStockQty(NumberUtil.sub(stockQty, normalQty));
//                        inventoryVariation.setChangeStorageQty(storageQty.negate());
//                        inventoryVariation.setChangeStockQty(normalQty.negate());
//                        qtySum = qtySum.subtract(NumberUtil.add(normalQty, storageQty));
//                    }


                    // storageQty.subtract(model.getQty());
                    break;
                case TargetTypeVo.RejectLock:
                    if (!IsOpenNegativeInventory) {
                        rejectLockQty.subtract(model.getQty());
                        qtySum = BigDecimal.ZERO;
                    } else if (rejectLockQty.getValue().compareTo(qtySum) >= 0) {
                        num = qtySum;
                        rejectLockQty.subtract(qtySum);
                        qtySum = BigDecimal.ZERO;
                    } else {
                        num = rejectLockQty.getValue();
                        qtySum = qtySum.subtract(rejectLockQty.getValue());
                        rejectLockQty.subtract(rejectLockQty.getValue());

                    }
                    // storageQty.subtract(model.getQty());
                    break;
                case TargetTypeVo.RejectWay:
                    if (!IsOpenNegativeInventory) {
                        rejectWayQty.subtract(model.getQty());
                        qtySum = BigDecimal.ZERO;
                    } else if (rejectWayQty.getValue().compareTo(qtySum) >= 0) {
                        num = qtySum;
                        rejectWayQty.subtract(qtySum);
                        qtySum = BigDecimal.ZERO;
                    } else {
                        num = rejectWayQty.getValue();
                        qtySum = qtySum.subtract(rejectWayQty.getValue());
                        rejectWayQty.subtract(rejectWayQty.getValue());

                    }
                    break;
                case TargetTypeVo.Inspected:
                    if (!IsOpenNegativeInventory) {
                        inspectedQty.subtract(model.getQty());
                        qtySum = BigDecimal.ZERO;
                    } else if (inspectedQty.getValue().compareTo(qtySum) >= 0) {
                        num = qtySum;
                        inspectedQty.subtract(qtySum);
                        qtySum = BigDecimal.ZERO;
                    } else {
                        num = inspectedQty.getValue();
                        qtySum = qtySum.subtract(inspectedQty.getValue());
                        inspectedQty.subtract(inspectedQty.getValue());
                    }
                    break;
                case TargetTypeVo.Picking:
                    if (!IsOpenNegativeInventory) {
                        pickingQty.subtract(model.getQty());
                        qtySum = BigDecimal.ZERO;
                    } else if (pickingQty.getValue().compareTo(qtySum) >= 0) {
                        num = qtySum;
                        pickingQty.subtract(qtySum);
                        qtySum = BigDecimal.ZERO;
                    } else {
                        num = pickingQty.getValue();
                        qtySum = qtySum.subtract(pickingQty.getValue());
                        pickingQty.subtract(pickingQty.getValue());

                    }
                    break;
            }
            //如果开启负库存  不在校验数量
//            if(getIsOpenNegativeInventory(model.getFromStockId())){
//                stockChangeCheck(model.getItem().getId(),"出库", stockQty, displayQty, defectQty, lockQty, wayQty,storageQty);
//            }

            // 处理入
            switch (model.getTo().getValue()) {
                case TargetTypeVo.Normal:
                    stockQty.add(num);
                    break;
                case TargetTypeVo.Display:
                    stockQty.add(num);
                    displayQty.add(num);
                    break;
                case TargetTypeVo.Defect:
                    stockQty.add(num);
                    defectQty.add(num);
                    break;
                case TargetTypeVo.Lock:
                    stockQty.add(num);
                    lockQty.add(num);
                    break;
                case TargetTypeVo.Way:
                    wayQty.add(num);
                    break;
                case TargetTypeVo.Storage:
                    storageQty.add(num);
                    break;
                case TargetTypeVo.RejectLock:
                    rejectLockQty.add(num);
                    break;
                case TargetTypeVo.RejectWay:
                    rejectWayQty.add(num);
                    break;
                case TargetTypeVo.Inspected:
                    inspectedQty.add(num);
                    break;
                case TargetTypeVo.Picking:
                    pickingQty.add(num);
                    break;
            }
            //如果开启负库存  不在校验数量
//            if(getIsOpenNegativeInventory(model.getToStockId())) {
//                stockChangeCheck(model.getItem().getId(), "入库", stockQty, displayQty, defectQty, lockQty, wayQty,storageQty);
//            }
            updateInventory.setStockQty(stockQty.getValue());
            inventoryVariation.setStockQty(stockQty.getValue());
            inventoryVariation.setChangeStockQty(stockQty.getChange());
            updateInventory.setLockQty(lockQty.getValue());
            inventoryVariation.setLockQty(lockQty.getValue());
            inventoryVariation.setChangeLockQty(lockQty.getChange());
            updateInventory.setWayQty(wayQty.getValue());
            inventoryVariation.setWayQty(wayQty.getValue());
            inventoryVariation.setChangeWayQty(wayQty.getChange());
            updateInventory.setDisplayQty(displayQty.getValue());
            inventoryVariation.setDisplayQty(displayQty.getValue());
            inventoryVariation.setChangeDisplayQty(displayQty.getChange());
            updateInventory.setDefectQty(defectQty.getValue());
            inventoryVariation.setDefectQty(defectQty.getValue());
            inventoryVariation.setChangeDefectQty(defectQty.getChange());
            updateInventory.setStorageQty(storageQty.getValue());
            inventoryVariation.setStorageQty(storageQty.getValue());
            inventoryVariation.setChangeStorageQty(storageQty.getChange());
            updateInventory.setRejectLockQty(rejectLockQty.getValue());
            inventoryVariation.setRejectLockQty(rejectLockQty.getValue());
            inventoryVariation.setChangeRejectLockQty(rejectLockQty.getChange());
            updateInventory.setRejectWayQty(rejectWayQty.getValue());
            inventoryVariation.setRejectWayQty(rejectWayQty.getValue());
            inventoryVariation.setChangeRejectWayQty(rejectWayQty.getChange());
            updateInventory.setInspectedQty(inspectedQty.getValue());
            inventoryVariation.setInspectedQty(inspectedQty.getValue());
            inventoryVariation.setChangeInspectedQty(inspectedQty.getChange());
            updateInventory.setPickingQty(pickingQty.getValue());
            inventoryVariation.setPickingQty(pickingQty.getValue());
            inventoryVariation.setChangePickingQty(pickingQty.getChange());

            //inventoryVariationMapper.insert(inventoryVariation);

            inventoryListReturnVo.setVariationIds(Collections.singletonList(inventoryVariation.getId()));
            inventoryListReturnVo.setUpdateIds(Collections.singletonList(inventory.getId()));

            updateInventory.setVersion(inventory.getVersion() + 1);
            final QueryWrapper<InventoryBatchNo> updateInventoryWrapper = Wrappers.<InventoryBatchNo>query()
                    .eq("id", inventory.getId())
                    .eq("version", inventory.getVersion());
            if (inventoryBatchNoMapper.update(updateInventory, updateInventoryWrapper) != 1) {
                throw new Exception("库存更新失败，库存可能在操作期间变更");
            }
        }
        return inventoryListReturnVo;
    }

    private void verificationOexchangeTargetTypeBatchNo(InventoryExchangeVo model, List<InventoryBatchNo> inventoryBatchNoList) throws Exception {
        //校验库存是否有那么多
        BigDecimal stockQty = inventoryBatchNoList.stream().filter(c -> c.getStockQty() != null).map(InventoryBatchNo::getStockQty).reduce(BigDecimal.ZERO, BigDecimal::add);
        BigDecimal lockQty = inventoryBatchNoList.stream().filter(c -> c.getLockQty() != null).map(InventoryBatchNo::getLockQty).reduce(BigDecimal.ZERO, BigDecimal::add);
        BigDecimal detDefectQty = inventoryBatchNoList.stream().filter(c -> c.getDefectQty() != null).map(InventoryBatchNo::getDefectQty).reduce(BigDecimal.ZERO, BigDecimal::add);
        BigDecimal displayQty = inventoryBatchNoList.stream().filter(c -> c.getDisplayQty() != null).map(InventoryBatchNo::getDisplayQty).reduce(BigDecimal.ZERO, BigDecimal::add);
        BigDecimal wayQty = inventoryBatchNoList.stream().filter(c -> c.getWayQty() != null).map(InventoryBatchNo::getWayQty).reduce(BigDecimal.ZERO, BigDecimal::add);
        BigDecimal storageQty = inventoryBatchNoList.stream().filter(c -> c.getStorageQty() != null).map(InventoryBatchNo::getStorageQty).reduce(BigDecimal.ZERO, BigDecimal::add);
        BigDecimal rejectLockQty = inventoryBatchNoList.stream().filter(c -> c.getRejectLockQty() != null).map(InventoryBatchNo::getRejectLockQty).reduce(BigDecimal.ZERO, BigDecimal::add);
        BigDecimal rejectWayQty = inventoryBatchNoList.stream().filter(c -> c.getRejectWayQty() != null).map(InventoryBatchNo::getRejectWayQty).reduce(BigDecimal.ZERO, BigDecimal::add);
        BigDecimal inspectedQty = inventoryBatchNoList.stream().filter(c -> c.getInspectedQty() != null).map(InventoryBatchNo::getInspectedQty).reduce(BigDecimal.ZERO, BigDecimal::add);
        BigDecimal pickingQty = inventoryBatchNoList.stream().filter(c -> c.getPickingQty() != null).map(InventoryBatchNo::getPickingQty).reduce(BigDecimal.ZERO, BigDecimal::add);

        //可用 = 可用 -对应的锁库 - 残次 - 陈列 不能大于当前的库存
        stockQty = stockQty.subtract(lockQty.add(detDefectQty).add(displayQty));
        //暂存 = 暂存 + 可用
        storageQty = NumberUtil.add(storageQty, stockQty);

        String itemIdName = "";
        if (StringUtils.isNotBlank(MaterialConfig.sql)) {
            try {
                String sql = String.format(MaterialConfig.sql, model.getItem().getId());
                itemIdName = inventoryMapper.selectMaterial(sql);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        switch (model.getFrom().getValue()) {
            case TargetTypeVo.Normal:

                if (stockQty.compareTo(model.getQty()) < 0) {
                    // throw new InventoryException(model.getItem().getId(), itemIdName+" 出库数量大于库存数量-锁库数量-残次数量 库存数："+stockQty.subtract(lockQty.add(detDefectQty)));
                    throw new InventoryException(model.getItem().getId(), itemIdName + "  库存不足：" + model.getQty().subtract(stockQty));
                }
                break;
            case TargetTypeVo.Lock:
                if (lockQty.compareTo(model.getQty()) < 0) {
                    throw new InventoryException(model.getItem().getId(), itemIdName + " 锁库库存不足：" + model.getQty().subtract(lockQty));
                }
                break;
            case TargetTypeVo.Display:
                if (displayQty.compareTo(model.getQty()) < 0) {
                    throw new InventoryException(model.getItem().getId(), itemIdName + " 展品库存不足：" + model.getQty().subtract(displayQty));
                }
                break;
            case TargetTypeVo.Defect:
                if (detDefectQty.compareTo(model.getQty()) < 0) {
                    throw new InventoryException(model.getItem().getId(), itemIdName + " 残次库存不足：" + model.getQty().subtract(detDefectQty));
                }
                break;
            case TargetTypeVo.Way:
                if (wayQty.compareTo(model.getQty()) < 0) {
                    throw new InventoryException(model.getItem().getId(), itemIdName + " 在途库存不足：" + model.getQty().subtract(wayQty));
                }
                break;
            case TargetTypeVo.Storage:
                if (storageQty.compareTo(model.getQty()) < 0) {
                    throw new InventoryException(model.getItem().getId(), itemIdName + " 暂存库存不足：" + model.getQty().subtract(storageQty));
                }
                break;
            case TargetTypeVo.RejectLock:
                if (rejectLockQty.compareTo(model.getQty()) < 0) {
                    throw new InventoryException(model.getItem().getId(), itemIdName + " 次品锁定库存不足：" + model.getQty().subtract(rejectLockQty));
                }
                break;
            case TargetTypeVo.RejectWay:
                if (rejectWayQty.compareTo(model.getQty()) < 0) {
                    throw new InventoryException(model.getItem().getId(), itemIdName + " 次品在途库存不足：" + model.getQty().subtract(rejectWayQty));
                }
                break;
            case TargetTypeVo.Inspected:
                if (inspectedQty.compareTo(model.getQty()) < 0) {
                    throw new InventoryException(model.getItem().getId(), itemIdName + " 待检库存不足：" + model.getQty().subtract(inspectedQty));
                }
                break;
            case TargetTypeVo.Picking:
                if (pickingQty.compareTo(model.getQty()) < 0) {
                    throw new InventoryException(model.getItem().getId(), itemIdName + " 拣货库存不足：" + model.getQty().subtract(pickingQty));
                }
                break;
            default:
                throw new Exception("出库源类型不明确");
        }
    }

    private InventoryListReturnVo exchangeTargetType(InventoryExchangeVo model) throws Exception {
        if (model.getFromBinIds() != null || model.getToBinIds() != null) {
            throw new Exception("此操作目前不支持带库位处理!");
        }

        Inventory inventory = getOne(queryWrapperInventoryexchangeSql(model));
        if (inventory == null) {
            if (getIsOpenNegativeInventory(model.getFromStockId())) {
                throw new Exception(getItemIdName(model.getItem().getId()) + "要操作的源库存不存在！");
            } else {
                //添加新的 在处理
                InventoryStorageVo inventoryStorageVo = new InventoryStorageVo();
                BeanUtils.copyProperties(model, inventoryStorageVo);
                inventoryStorageVo.setQty(BigDecimal.valueOf(0));
                inventoryStorageVo.setTo(model.getFrom());
                inventoryStorageVo.setStockId(model.getFromStockId());
                InventoryListReturnVo inventoryListReturnVo = new InventoryListReturnVo();
                List<BinIdsVo> binIdsVos = new ArrayList<>();
                storageInsert(inventoryStorageVo, inventoryListReturnVo, binIdsVos);
                inventory = getOne(queryWrapperInventoryexchangeSql(model));
            }
        }

        ChangeNum stockQty = new ChangeNum(inventory.getStockQty());
        ChangeNum lockQty = new ChangeNum(inventory.getLockQty());
        ChangeNum displayQty = new ChangeNum(inventory.getDisplayQty());
        ChangeNum defectQty = new ChangeNum(inventory.getDefectQty());
        ChangeNum wayQty = new ChangeNum(inventory.getWayQty());
        ChangeNum storageQty = new ChangeNum(inventory.getStorageQty());
        ChangeNum rejectLockQty = new ChangeNum(inventory.getRejectLockQty());
        ChangeNum rejectWayQty = new ChangeNum(inventory.getRejectWayQty());
        ChangeNum inspectedQty = new ChangeNum(inventory.getInspectedQty());
        ChangeNum pickingQty = new ChangeNum(inventory.getPickingQty());

        InventoryListReturnVo inventoryListReturnVo = new InventoryListReturnVo();
        InventoryVariation inventoryVariation = new InventoryVariation();
        BeanUtils.copyProperties(model, inventoryVariation);
        inventoryVariation.setChangeType("Exchange");
        inventoryVariation.setStockId(model.getFromStockId());
        inventoryVariation.setFromType(model.getFrom().getValue());
        inventoryVariation.setToType(model.getTo().getValue());
        inventoryVariation.setItemId(model.getItem().getId());
        inventoryVariation.setOperateTime(new Date());

        Inventory updateInventory = new Inventory();

        // 处理出
        switch (model.getFrom().getValue()) {
            case TargetTypeVo.Normal:
                stockQty.subtract(model.getQty());
                break;
            case TargetTypeVo.Display:
                stockQty.subtract(model.getQty());
                displayQty.subtract(model.getQty());
                break;
            case TargetTypeVo.Defect:
                stockQty.subtract(model.getQty());
                defectQty.subtract(model.getQty());
                break;
            case TargetTypeVo.Lock:
                stockQty.subtract(model.getQty());
                lockQty.subtract(model.getQty());
                break;
            case TargetTypeVo.Way:
                wayQty.subtract(model.getQty());
                break;
            case TargetTypeVo.Storage:

                if (storageQty.getValue().compareTo(model.getQty()) >= 0) {
                    storageQty.subtract(model.getQty());
                } else {
                    stockQty.subtract(model.getQty().subtract(storageQty.getValue()));
                    storageQty.subtract(storageQty.getValue());
                }
                //  storageQty.subtract(model.getQty());
                break;
            case TargetTypeVo.RejectLock:
                rejectLockQty.subtract(model.getQty());
                break;
            case TargetTypeVo.RejectWay:
                rejectWayQty.subtract(model.getQty());
                break;
            case TargetTypeVo.Inspected:
                inspectedQty.subtract(model.getQty());
                break;
            case TargetTypeVo.Picking:
                pickingQty.subtract(model.getQty());
                break;
        }
        //如果开启负库存  不在校验数量
        if (getIsOpenNegativeInventory(model.getFromStockId())) {
            stockChangeCheck(model.getItem().getId(), "出库", stockQty, displayQty, defectQty, lockQty, wayQty, storageQty, rejectLockQty, rejectWayQty, inspectedQty, pickingQty);
        }
        // 处理入
        switch (model.getTo().getValue()) {
            case TargetTypeVo.Normal:
                stockQty.add(model.getQty());
                break;
            case TargetTypeVo.Display:
                stockQty.add(model.getQty());
                displayQty.add(model.getQty());
                break;
            case TargetTypeVo.Defect:
                stockQty.add(model.getQty());
                defectQty.add(model.getQty());
                break;
            case TargetTypeVo.Lock:
                stockQty.add(model.getQty());
                lockQty.add(model.getQty());
                break;
            case TargetTypeVo.Way:
                wayQty.add(model.getQty());
                break;
            case TargetTypeVo.Storage:
                storageQty.add(model.getQty());
                break;
            case TargetTypeVo.RejectLock:
                rejectLockQty.add(model.getQty());
                break;
            case TargetTypeVo.RejectWay:
                rejectWayQty.add(model.getQty());
                break;
            case TargetTypeVo.Inspected:
                inspectedQty.add(model.getQty());
                break;
            case TargetTypeVo.Picking:
                pickingQty.add(model.getQty());
                break;
        }
        //如果开启负库存  不在校验数量
        if (getIsOpenNegativeInventory(model.getToStockId())) {
            stockChangeCheck(model.getItem().getId(), "入库", stockQty, displayQty, defectQty, lockQty, wayQty, storageQty, rejectLockQty, rejectWayQty, inspectedQty, pickingQty);
        }
        updateInventory.setStockQty(stockQty.getValue());
        inventoryVariation.setStockQty(stockQty.getValue());
        inventoryVariation.setChangeStockQty(stockQty.getChange());
        updateInventory.setLockQty(lockQty.getValue());
        inventoryVariation.setLockQty(lockQty.getValue());
        inventoryVariation.setChangeLockQty(lockQty.getChange());
        updateInventory.setWayQty(wayQty.getValue());
        inventoryVariation.setWayQty(wayQty.getValue());
        inventoryVariation.setChangeWayQty(wayQty.getChange());
        updateInventory.setDisplayQty(displayQty.getValue());
        inventoryVariation.setDisplayQty(displayQty.getValue());
        inventoryVariation.setChangeDisplayQty(displayQty.getChange());
        updateInventory.setDefectQty(defectQty.getValue());
        inventoryVariation.setDefectQty(defectQty.getValue());
        inventoryVariation.setChangeDefectQty(defectQty.getChange());
        updateInventory.setStorageQty(storageQty.getValue());
        inventoryVariation.setStorageQty(storageQty.getValue());
        inventoryVariation.setChangeStorageQty(storageQty.getChange());
        updateInventory.setRejectLockQty(rejectLockQty.getValue());
        inventoryVariation.setRejectLockQty(rejectLockQty.getValue());
        inventoryVariation.setChangeRejectLockQty(rejectLockQty.getChange());
        updateInventory.setRejectWayQty(rejectWayQty.getValue());
        inventoryVariation.setRejectWayQty(rejectWayQty.getValue());
        inventoryVariation.setChangeRejectWayQty(rejectWayQty.getChange());
        updateInventory.setInspectedQty(inspectedQty.getValue());
        inventoryVariation.setInspectedQty(inspectedQty.getValue());
        inventoryVariation.setChangeInspectedQty(inspectedQty.getChange());
        updateInventory.setPickingQty(pickingQty.getValue());
        inventoryVariation.setPickingQty(pickingQty.getValue());
        inventoryVariation.setChangePickingQty(pickingQty.getChange());
        inventoryVariationMapper.insert(inventoryVariation);

        inventoryListReturnVo.setVariationIds(Collections.singletonList(inventoryVariation.getId()));
        inventoryListReturnVo.setUpdateIds(Collections.singletonList(inventory.getId()));

        updateInventory.setVersion(inventory.getVersion() + 1);
        final QueryWrapper<Inventory> updateInventoryWrapper = Wrappers.<Inventory>query()
                .eq("id", inventory.getId())
                .eq("version", inventory.getVersion());
        if (inventoryMapper.update(updateInventory, updateInventoryWrapper) != 1) {
            throw new Exception("库存更新失败，库存可能在操作期间变更");
        }

        return inventoryListReturnVo;
    }

    private void stockChangeCheck(Long itemId, String action, ChangeNum stockQty, ChangeNum displayQty, ChangeNum defectQty, ChangeNum lockQty, ChangeNum wayQty, ChangeNum storageQty, ChangeNum rejectLockQty, ChangeNum rejectWayQty, ChangeNum inspectedQty, ChangeNum pickingQty) throws Exception {

        //暂存 = 暂存 + 可用
        storageQty = new ChangeNum(NumberUtil.add(storageQty.getValue(), stockQty.getValue()));

        String itemIdName = "";
        if (StringUtils.isNotBlank(MaterialConfig.sql)) {
            try {
                String sql = String.format(MaterialConfig.sql, itemId);
                itemIdName = inventoryMapper.selectMaterial(sql);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        if (stockQty.isNegative()) {
            throw new Exception(itemIdName + action + "总库存不足：" + stockQty.newValue.negate());
        }
        if (displayQty.isNegative()) {
            throw new Exception(itemIdName + action + "展示库存不足：" + displayQty.newValue.negate());
        }
        if (defectQty.isNegative()) {
            throw new Exception(itemIdName + action + "残次库存不足：" + defectQty.newValue.negate());
        }
        if (lockQty.isNegative()) {
            throw new Exception(itemIdName + action + "锁定库存不足：" + lockQty.newValue.negate());
        }
        if (wayQty.isNegative()) {
            throw new Exception(itemIdName + action + "在途库存不足：" + wayQty.newValue.negate());
        }
        if (storageQty.isNegative()) {
            throw new Exception(itemIdName + action + "暂存库存不足：" + storageQty.newValue.negate());
        }
        if (rejectLockQty.isNegative()) {
            throw new Exception(itemIdName + action + "次品锁定库存不足：" + rejectLockQty.newValue.negate());
        }
        if (rejectWayQty.isNegative()) {
            throw new Exception(itemIdName + action + "次品在途库存不足：" + rejectLockQty.newValue.negate());
        }
        if (inspectedQty.isNegative()) {
            throw new Exception(itemIdName + action + "待检库存不足：" + rejectLockQty.newValue.negate());
        }
        if (pickingQty.isNegative()) {
            throw new Exception(itemIdName + action + "拣货库存不足：" + pickingQty.newValue.negate());
        }
        if (stockQty.getNotNullValue().subtract(displayQty.getNotNullValue()).subtract(defectQty.getNotNullValue()).subtract(lockQty.getNotNullValue()).compareTo(BigDecimal.ZERO) < 0) {
            throw new Exception(itemIdName + action + "普通库存不足：" + stockQty.getNotNullValue().subtract(displayQty.getNotNullValue()).subtract(defectQty.getNotNullValue()).subtract(lockQty.getNotNullValue()).negate());
        }
    }


    /**
     * 调拨出库  转对应实体直接调用方法
     * 自动完成分别调用出仓的 outbound 和入仓的 storage，对应变更的 operate（操作名称）自动配置为 “调拨出库”与“调拨入库”
     *
     * @param model
     * @return
     * @throws Exception
     */
    private InventoryListReturnVo exchangeAllot(InventoryExchangeVo model) throws Exception {
        //出库
        InventoryOutboundVo inventoryOutboundVo = new InventoryOutboundVo();
        BeanUtils.copyProperties(model, inventoryOutboundVo);
        inventoryOutboundVo.setOperate("调拨出库");
        inventoryOutboundVo.setStockId(model.getFromStockId());
        inventoryOutboundVo.setBinIds(model.getFromBinIds());
        InventoryListReturnVo outbound = outboundItem(inventoryOutboundVo);

        //入库 入库需要
        InventoryStorageVo inventoryStorageVo = new InventoryStorageVo();
        BeanUtils.copyProperties(model, inventoryStorageVo);
        inventoryStorageVo.setOperate("调拨入库");
        inventoryStorageVo.setStockId(model.getToStockId());
        inventoryStorageVo.setBinIds(model.getToBinIds());
        InventoryListReturnVo storage = storageItem(inventoryStorageVo);

        InventoryListReturnVo inventoryListReturnVo = new InventoryListReturnVo();

        List<Long> addIds = new ArrayList<>();
        if (outbound.getAddIds() != null) {
            addIds.addAll(outbound.getAddIds());
        }
        if (storage.getAddIds() != null) {
            addIds.addAll(storage.getAddIds());
        }
        inventoryListReturnVo.setAddIds(addIds);
        List<Long> updateIds = new ArrayList<>();
        if (outbound.getUpdateIds() != null) {
            updateIds.addAll(outbound.getUpdateIds());
        }
        if (storage.getUpdateIds() != null) {
            updateIds.addAll(storage.getUpdateIds());
        }
        inventoryListReturnVo.setUpdateIds(updateIds);
        List<Long> removeIds = new ArrayList<>();
        if (outbound.getRemoveIds() != null) {
            removeIds.addAll(outbound.getRemoveIds());
        }
        if (storage.getRemoveIds() != null) {
            removeIds.addAll(storage.getRemoveIds());
        }
        inventoryListReturnVo.setRemoveIds(removeIds);
        List<Long> variationIds = new ArrayList<>();
        if (outbound.getVariationIds() != null) {
            variationIds.addAll(outbound.getVariationIds());
        }
        if (storage.getVariationIds() != null) {
            variationIds.addAll(storage.getVariationIds());
        }
        inventoryListReturnVo.setVariationIds(variationIds);
        return inventoryListReturnVo;
    }

    /**
     * 仓库转移 批次库存
     *
     * @param model
     * @param fromBinIdsVos
     * @param toBinIdsVos
     * @return
     */
    private InventoryListReturnVo exchangeShiftBatchNo(InventoryExchangeVo model, List<BinIdsVo> fromBinIdsVos, List<BinIdsVo> toBinIdsVos) throws Exception {
        InventoryListReturnVo inventoryListReturnVo = new InventoryListReturnVo();
        InventoryVariation inventoryVariation = new InventoryVariation();
        BeanUtils.copyProperties(model, inventoryVariation);
        inventoryVariation.setChangeType("Exchange");
        inventoryVariation.setStockId(model.getFromStockId());
        inventoryVariation.setFromType(model.getFrom().getValue());
        inventoryVariation.setToType(model.getTo().getValue());
        inventoryVariation.setItemId(model.getItem().getId());
        inventoryVariation.setOperateTime(new Date());
        //查询对应的仓库 -库存  如果数量不足  提示报错
//        for (BinIdsVo binIdsVo: fromBinIdsVos){
//            // 20230317-- 流转应该可以同时操作多条仓库记录 这块应该是查询一个符合条件的list 判断下总数量是否大于总数 大于直接抛异常
//            String descOrAsc = queryWrapperInventoryPlacementexchangeFromShiftDescOrAsc(model);
//            List<InventoryPlacement> inventoryPlacementList= inventoryPlacementMapper.queryWrapperInventoryPlacementexchangeFromShiftSqlList(model,binIdsVo.getBinId(),descOrAsc);
//            if (CollectionUtils.isEmpty(inventoryPlacementList)) {
//                throw new Exception(getItemIdName(model.getItem().getId())+"没有对应库位内码");
//            }
//            BigDecimal stockQtySum= inventoryPlacementList.stream().map(InventoryPlacement::getStockQty).reduce(BigDecimal.ZERO, BigDecimal::add);
//            if(stockQtySum.compareTo(new BigDecimal(binIdsVo.getQty()))==-1){
//                throw new Exception(getItemIdName(model.getItem().getId())+"库存货位放置表没有那么多库存");
//            }
//            BigDecimal qtySum= new BigDecimal(binIdsVo.getQty());
//            for (InventoryPlacement inventoryPlacement : inventoryPlacementList) {
//                LambdaUpdateChainWrapper<InventoryPlacement> inventoryPlacementUpdateChainWrapper = new LambdaUpdateChainWrapper<>(inventoryPlacementMapper);
//                if(qtySum.compareTo(BigDecimal.ZERO)==0){
//                    break;
//                }else if(qtySum.compareTo(inventoryPlacement.getStockQty())>=0){
//                    qtySum=qtySum.subtract(inventoryPlacement.getStockQty());
//                    inventoryPlacementUpdateChainWrapper.set(InventoryPlacement::getStockQty, BigDecimal.ZERO);
//                }else if (qtySum.compareTo(inventoryPlacement.getStockQty())==-1){
//                    inventoryPlacementUpdateChainWrapper.set(InventoryPlacement::getStockQty, inventoryPlacement.getStockQty().subtract(qtySum));
//                    qtySum=BigDecimal.ZERO;
//                }
//                inventoryPlacementUpdateChainWrapper.eq(InventoryPlacement::getId, inventoryPlacement.getId());
//                inventoryPlacementUpdateChainWrapper.eq(InventoryPlacement::getVersion, inventoryPlacement.getVersion());
//                inventoryPlacementUpdateChainWrapper.set(InventoryPlacement::getVersion, inventoryPlacement.getVersion() + 1);
//                if(!inventoryPlacementUpdateChainWrapper.update()) {
//                    throw new Exception("数据版本错误，更新失败");
//                }
//            }
//
//        }
        LambdaQueryWrapper<InventoryBatchNo> queryWrapper = queryWrapperInventoryexchangeSqlBatchNo(model);
        List<InventoryBatchNo> inventory = inventoryBatchNoMapper.selectList(queryWrapper);
        //查询对应的仓库 -库存  如果没有 添加 有自动添加数量
//        for (BinIdsVo binIdsVo: toBinIdsVos){
//            String descOrAsc = queryWrapperInventoryPlacementexchangeFromShiftDescOrAsc(model);
//            List<InventoryPlacement> inventoryPlacementList= inventoryPlacementMapper.queryWrapperInventoryPlacementexchangeFromShiftSql(model,binIdsVo.getBinId(),descOrAsc);
//            InventoryPlacement inventoryPlacement=new InventoryPlacement();
//            if (CollectionUtils.isNotEmpty(inventoryPlacementList)){
//                inventoryPlacement=inventoryPlacementList.get(0);
//            }else {
//                inventoryPlacement= null;
//            }
//            if(inventoryPlacement!=null){
//                LambdaUpdateChainWrapper<InventoryPlacement> inventoryPlacementUpdateChainWrapper = new LambdaUpdateChainWrapper<>(inventoryPlacementMapper);
//                inventoryPlacementUpdateChainWrapper.eq(InventoryPlacement::getId, inventoryPlacement.getId());
//                inventoryPlacementUpdateChainWrapper.eq(InventoryPlacement::getVersion, inventoryPlacement.getVersion());
//                inventoryPlacementUpdateChainWrapper.set(InventoryPlacement::getVersion, inventoryPlacement.getVersion() + 1);
//                inventoryPlacementUpdateChainWrapper.set(InventoryPlacement::getStockQty, inventoryPlacement.getStockQty().add(new BigDecimal(binIdsVo.getQty())));
//                if(!inventoryPlacementUpdateChainWrapper.update()) {
//                    throw new Exception("数据版本错误，更新失败");
//                }
//            }else {
//                //新增
//                InventoryPlacement insertInventoryPlacement=new InventoryPlacement();
//                BeanUtils.copyProperties(model,insertInventoryPlacement);
//                insertInventoryPlacement.setStockId(model.getFromStockId());
//                insertInventoryPlacement.setBinId(binIdsVo.getBinId());
//                insertInventoryPlacement.setStockQty(new BigDecimal(binIdsVo.getQty()));
//                if(inventory!=null&&inventory.size()>0){
//                    insertInventoryPlacement.setAuxId(inventory.get(0).getAuxId());
//                    insertInventoryPlacement.setAuxQty(inventory.get(0).getAuxQty());
//                    insertInventoryPlacement.setProductionDate(inventory.get(0).getProductionDate());
//                    insertInventoryPlacement.setExpiryDate(inventory.get(0).getExpiryDate());
//                    insertInventoryPlacement.setShelfLife(inventory.get(0).getShelfLife());
//                }
//                insertInventoryPlacement.setItemId(model.getItem().getId());
//                if(StringUtils.isBlank(model.getBatchNo())){
//                    insertInventoryPlacement.setBatchNo(null);
//                }
//                inventoryPlacementMapper.insert(insertInventoryPlacement);
//            }
//        }
        //inventoryVariationMapper.insert(inventoryVariation);
        List<Long> variationIds = new ArrayList<>();
        variationIds.add(inventoryVariation.getId());
        inventoryListReturnVo.setVariationIds(variationIds);
        return inventoryListReturnVo;
    }

    /**
     * 仓库转移
     *
     * @param model
     * @param fromBinIdsVos
     * @param toBinIdsVos
     * @return
     */
    private InventoryListReturnVo exchangeShift(InventoryExchangeVo model, List<BinIdsVo> fromBinIdsVos, List<BinIdsVo> toBinIdsVos) throws Exception {
        InventoryListReturnVo inventoryListReturnVo = new InventoryListReturnVo();
        InventoryVariation inventoryVariation = new InventoryVariation();
        BeanUtils.copyProperties(model, inventoryVariation);
        inventoryVariation.setChangeType("Exchange");
        inventoryVariation.setStockId(model.getFromStockId());
        inventoryVariation.setFromType(model.getFrom().getValue());
        inventoryVariation.setToType(model.getTo().getValue());
        inventoryVariation.setItemId(model.getItem().getId());
        inventoryVariation.setOperateTime(new Date());
        LambdaQueryWrapper<Inventory> queryWrapper = queryWrapperInventoryexchangeSql(model);
        Inventory inventory = this.getOne(queryWrapper, false);
        //查询对应的仓库 -库存  如果数量不足  提示报错
        for (BinIdsVo binIdsVo : fromBinIdsVos) {
            if (ObjectUtils.isEmpty(binIdsVo.getBinId())) {
                if (model.getFrom().getValue().equals(TargetTypeVo.Defect)) {
                    binIdsVo.setBinId(getSearchByWarehouseBin(model.getFromStockId(), model.getShopId(), model.getFnSku(), model.getItem().getId(), 2));
                } else {
                    binIdsVo.setBinId(getSearchByWarehouseBin(model.getFromStockId(), model.getShopId(), model.getFnSku(), model.getItem().getId(), 1));
                }
            }
            InventoryPlacementVariation inventoryPlacementVariation = new InventoryPlacementVariation();
            BeanUtils.copyProperties(model, inventoryVariation);
            inventoryPlacementVariation.setChangeType("Exchange");
            inventoryPlacementVariation.setStockId(model.getFromStockId());
            inventoryPlacementVariation.setFromType(model.getFromBinIdsType().getValue());
            inventoryPlacementVariation.setToType(model.getToBinIdsType().getValue());
            inventoryPlacementVariation.setItemId(model.getItem().getId());
            inventoryPlacementVariation.setOperateTime(new Date());
            inventoryPlacementVariation.setBinId(binIdsVo.getBinId());
            inventoryPlacementVariation.setShopId(model.getShopId());
            inventoryPlacementVariation.setFormNum(model.getFormNum());
            inventoryPlacementVariation.setFormOperator(model.getFormOperator());
            inventoryPlacementVariation.setOperateKey(model.getOperateKey());
            inventoryPlacementVariation.setFnSku(model.getFnSku());
            inventoryPlacementVariation.setDocumentType(model.getDocumentType());
            // 20230317-- 流转应该可以同时操作多条仓库记录 这块应该是查询一个符合条件的list 判断下总数量是否大于总数 大于直接抛异常
            String descOrAsc = queryWrapperInventoryPlacementexchangeFromShiftDescOrAsc(model);
            List<InventoryPlacement> inventoryPlacementList = inventoryPlacementMapper.queryWrapperInventoryPlacementexchangeFromShiftSqlList(model, binIdsVo.getBinId(), descOrAsc);
            if (CollectionUtils.isEmpty(inventoryPlacementList)) {
                if (getIsOpenNegativeInventory(model.getFromStockId())) {
                    throw new Exception(getItemIdName(model.getItem().getId()) + "没有对应库位内码");
                } else {
                    //新增
                    InventoryPlacement insertInventoryPlacement = new InventoryPlacement();
                    BeanUtils.copyProperties(model, insertInventoryPlacement);
                    insertInventoryPlacement.setStockId(model.getFromStockId());
                    insertInventoryPlacement.setBinId(binIdsVo.getBinId());
                    //insertInventoryPlacement.setStockQty(new BigDecimal(binIdsVo.getQty()));
                    if (inventory != null) {
                        insertInventoryPlacement.setAuxId(inventory.getAuxId());
                        insertInventoryPlacement.setAuxQty(inventory.getAuxQty());
                        insertInventoryPlacement.setProductionDate(inventory.getProductionDate());
                        insertInventoryPlacement.setExpiryDate(inventory.getExpiryDate());
                        insertInventoryPlacement.setShelfLife(inventory.getShelfLife());
                    }
                    insertInventoryPlacement.setItemId(model.getItem().getId());
                    if (StringUtils.isBlank(model.getBatchNo())) {
                        insertInventoryPlacement.setBatchNo(null);
                    }
                    inventoryPlacementMapper.insert(insertInventoryPlacement);
                    inventoryPlacementList = inventoryPlacementMapper.queryWrapperInventoryPlacementexchangeFromShiftSqlList(model, binIdsVo.getBinId(), descOrAsc);
                }
            }
            BigDecimal stockQtySum = inventoryPlacementList.stream().filter(c -> c.getStockQty() != null).map(InventoryPlacement::getStockQty).reduce(BigDecimal.ZERO, BigDecimal::add);
            BigDecimal lockQtySum = inventoryPlacementList.stream().filter(c -> c.getLockQty() != null).map(InventoryPlacement::getLockQty).reduce(BigDecimal.ZERO, BigDecimal::add);
            BigDecimal wayQtySum = inventoryPlacementList.stream().filter(c -> c.getWayQty() != null).map(InventoryPlacement::getWayQty).reduce(BigDecimal.ZERO, BigDecimal::add);

            // inventoryPlacementVariation.setWayQty(wayQtySum);
            //  inventoryPlacementVariation.setLockQty(lockQtySum);
            // inventoryPlacementVariation.setStockQty(stockQtySum);
            //如果开启负库存  不在校验库位数量
            if (getIsOpenNegativeInventory(model.getFromStockId())) {
                switch (model.getFromBinIdsType().getValue()) {
                    case TargetTypeVo.Normal:
                        if (stockQtySum.compareTo(new BigDecimal(binIdsVo.getQty())) == -1) {
                            throw new Exception(getItemIdName(model.getItem().getId()) + "库存货位放置表正常库存不足");
                        }
                        inventoryPlacementVariation.setStockQty(stockQtySum.subtract(new BigDecimal(binIdsVo.getQty())));
                        inventoryPlacementVariation.setChangeStockQty(new BigDecimal(binIdsVo.getQty()).negate());
                        break;
                    case TargetTypeVo.Lock:
                        if (lockQtySum.compareTo(new BigDecimal(binIdsVo.getQty())) == -1) {
                            throw new Exception(getItemIdName(model.getItem().getId()) + "库存货位放置表锁定库存不足");
                        }
                        inventoryPlacementVariation.setLockQty(lockQtySum.subtract(new BigDecimal(binIdsVo.getQty())));
                        inventoryPlacementVariation.setChangeLockQty(new BigDecimal(binIdsVo.getQty()).negate());
                        break;
                    case TargetTypeVo.Way:
                        if (wayQtySum.compareTo(new BigDecimal(binIdsVo.getQty())) == -1) {
                            throw new Exception(getItemIdName(model.getItem().getId()) + "库存货位放置表在途库存不足");
                        }
                        inventoryPlacementVariation.setWayQty(wayQtySum.subtract(new BigDecimal(binIdsVo.getQty())));
                        inventoryPlacementVariation.setChangeWayQty(new BigDecimal(binIdsVo.getQty()).negate());
                        break;
                    default:
                        throw new Exception("出库位类型不明确");
                }
            } else {
                switch (model.getFromBinIdsType().getValue()) {
                    case TargetTypeVo.Normal:
                        inventoryPlacementVariation.setStockQty(stockQtySum.subtract(new BigDecimal(binIdsVo.getQty())));
                        inventoryPlacementVariation.setChangeStockQty(new BigDecimal(binIdsVo.getQty()));
                        break;
                    case TargetTypeVo.Lock:
                        inventoryPlacementVariation.setLockQty(lockQtySum.subtract(new BigDecimal(binIdsVo.getQty())));
                        inventoryPlacementVariation.setChangeLockQty(new BigDecimal(binIdsVo.getQty()));
                        break;
                    case TargetTypeVo.Way:
                        inventoryPlacementVariation.setWayQty(wayQtySum.subtract(new BigDecimal(binIdsVo.getQty())));
                        inventoryPlacementVariation.setChangeWayQty(new BigDecimal(binIdsVo.getQty()));
                        break;
                    default:
                        throw new Exception("出库位类型不明确");
                }
            }
            inventoryPlacementVariationMapper.insert(inventoryPlacementVariation);
            BigDecimal qtySum = new BigDecimal(binIdsVo.getQty());
            for (InventoryPlacement inventoryPlacement : inventoryPlacementList) {
                LambdaUpdateChainWrapper<InventoryPlacement> inventoryPlacementUpdateChainWrapper = new LambdaUpdateChainWrapper<>(inventoryPlacementMapper);
                switch (model.getFromBinIdsType().getValue()) {
                    case TargetTypeVo.Normal:
                        if (inventoryPlacement.getStockQty() == null) {
                            inventoryPlacement.setStockQty(new BigDecimal(0));
                        }
                        if (qtySum.compareTo(BigDecimal.ZERO) == 0) {
                            break;
                        } else if (!getIsOpenNegativeInventory(model.getFromStockId())) {
                            inventoryPlacementUpdateChainWrapper.set(InventoryPlacement::getStockQty, inventoryPlacement.getStockQty().subtract(qtySum));
                            qtySum = BigDecimal.ZERO;
                        } else if (qtySum.compareTo(inventoryPlacement.getStockQty()) >= 0) {
                            qtySum = qtySum.subtract(inventoryPlacement.getStockQty());
                            inventoryPlacementUpdateChainWrapper.set(InventoryPlacement::getStockQty, BigDecimal.ZERO);
                            //inventoryPlacementUpdateChainWrapper.set(InventoryPlacement::getStockQty, inventoryPlacement.getStockQty().subtract(qtySum));
                            //qtySum=BigDecimal.ZERO;
                        } else if (qtySum.compareTo(inventoryPlacement.getStockQty()) == -1) {
                            inventoryPlacementUpdateChainWrapper.set(InventoryPlacement::getStockQty, inventoryPlacement.getStockQty().subtract(qtySum));
                            qtySum = BigDecimal.ZERO;
                        }
                        inventoryPlacementUpdateChainWrapper.eq(InventoryPlacement::getId, inventoryPlacement.getId());
                        inventoryPlacementUpdateChainWrapper.eq(InventoryPlacement::getVersion, inventoryPlacement.getVersion());
                        inventoryPlacementUpdateChainWrapper.set(InventoryPlacement::getVersion, inventoryPlacement.getVersion() + 1);
                        if (!inventoryPlacementUpdateChainWrapper.update()) {
                            throw new Exception("数据版本错误，更新失败");
                        }
                        break;
                    case TargetTypeVo.Lock:
                        if (inventoryPlacement.getLockQty() == null) {
                            inventoryPlacement.setLockQty(new BigDecimal(0));
                        }
                        if (qtySum.compareTo(BigDecimal.ZERO) == 0) {
                            break;
                        } else if (!getIsOpenNegativeInventory(model.getFromStockId())) {
                            inventoryPlacementUpdateChainWrapper.set(InventoryPlacement::getLockQty, inventoryPlacement.getLockQty().subtract(qtySum));
                            qtySum = BigDecimal.ZERO;
                        } else if (qtySum.compareTo(inventoryPlacement.getLockQty()) >= 0) {
                            qtySum = qtySum.subtract(inventoryPlacement.getLockQty());
                            inventoryPlacementUpdateChainWrapper.set(InventoryPlacement::getLockQty, BigDecimal.ZERO);
                            //inventoryPlacementUpdateChainWrapper.set(InventoryPlacement::getStockQty, inventoryPlacement.getStockQty().subtract(qtySum));
                            //qtySum=BigDecimal.ZERO;
                        } else if (qtySum.compareTo(inventoryPlacement.getLockQty()) == -1) {
                            inventoryPlacementUpdateChainWrapper.set(InventoryPlacement::getLockQty, inventoryPlacement.getLockQty().subtract(qtySum));
                            qtySum = BigDecimal.ZERO;
                        }
                        inventoryPlacementUpdateChainWrapper.eq(InventoryPlacement::getId, inventoryPlacement.getId());
                        inventoryPlacementUpdateChainWrapper.eq(InventoryPlacement::getVersion, inventoryPlacement.getVersion());
                        inventoryPlacementUpdateChainWrapper.set(InventoryPlacement::getVersion, inventoryPlacement.getVersion() + 1);
                        if (!inventoryPlacementUpdateChainWrapper.update()) {
                            throw new Exception("数据版本错误，更新失败");
                        }
                        break;
                    case TargetTypeVo.Way:
                        if (inventoryPlacement.getWayQty() == null) {
                            inventoryPlacement.setWayQty(new BigDecimal(0));
                        }
                        if (qtySum.compareTo(BigDecimal.ZERO) == 0) {
                            break;
                        } else if (!getIsOpenNegativeInventory(model.getFromStockId())) {
                            inventoryPlacementUpdateChainWrapper.set(InventoryPlacement::getWayQty, inventoryPlacement.getWayQty().subtract(qtySum));
                            qtySum = BigDecimal.ZERO;
                        } else if (qtySum.compareTo(inventoryPlacement.getWayQty()) >= 0) {
                            qtySum = qtySum.subtract(inventoryPlacement.getWayQty());
                            inventoryPlacementUpdateChainWrapper.set(InventoryPlacement::getWayQty, BigDecimal.ZERO);
                            //inventoryPlacementUpdateChainWrapper.set(InventoryPlacement::getStockQty, inventoryPlacement.getStockQty().subtract(qtySum));
                            //qtySum=BigDecimal.ZERO;
                        } else if (qtySum.compareTo(inventoryPlacement.getWayQty()) == -1) {
                            inventoryPlacementUpdateChainWrapper.set(InventoryPlacement::getWayQty, inventoryPlacement.getWayQty().subtract(qtySum));
                            qtySum = BigDecimal.ZERO;
                        }
                        inventoryPlacementUpdateChainWrapper.eq(InventoryPlacement::getId, inventoryPlacement.getId());
                        inventoryPlacementUpdateChainWrapper.eq(InventoryPlacement::getVersion, inventoryPlacement.getVersion());
                        inventoryPlacementUpdateChainWrapper.set(InventoryPlacement::getVersion, inventoryPlacement.getVersion() + 1);
                        if (!inventoryPlacementUpdateChainWrapper.update()) {
                            throw new Exception("数据版本错误，更新失败");
                        }
                        break;
                    default:
                        throw new Exception("出库位类型不明确");

                }
            }

//            LambdaQueryWrapper<InventoryPlacement> queryWrapper= queryWrapperInventoryPlacementexchangeFromShiftSql(model,binIdsVo.getBinId());
//            InventoryPlacement inventoryPlacement= inventoryPlacementMapper.selectOne(queryWrapper.last(" limit 1"));
//            String descOrAsc = queryWrapperInventoryPlacementexchangeFromShiftDescOrAsc(model);
//            InventoryPlacement inventoryPlacement= inventoryPlacementMapper.queryWrapperInventoryPlacementexchangeFromShiftSql(model,binIdsVo.getBinId(),descOrAsc);
//            if(inventoryPlacement!=null){
//                if(inventoryPlacement.getStockQty().compareTo(new BigDecimal(binIdsVo.getQty()))==-1){
//                    throw new Exception("库存货位放置表没有那么多库存");
//                }
//                LambdaUpdateChainWrapper<InventoryPlacement> inventoryPlacementUpdateChainWrapper = new LambdaUpdateChainWrapper<>(inventoryPlacementMapper);
//                inventoryPlacementUpdateChainWrapper.eq(InventoryPlacement::getId, inventoryPlacement.getId());
//                inventoryPlacementUpdateChainWrapper.eq(InventoryPlacement::getVersion, inventoryPlacement.getVersion());
//                inventoryPlacementUpdateChainWrapper.set(InventoryPlacement::getVersion, inventoryPlacement.getVersion() + 1);
//                inventoryPlacementUpdateChainWrapper.set(InventoryPlacement::getStockQty, inventoryPlacement.getStockQty().subtract(new BigDecimal(binIdsVo.getQty())));
//                if(!inventoryPlacementUpdateChainWrapper.update()) {
//                    throw new Exception("数据版本错误，更新失败");
//                }
////                InventoryPlacement updateInventoryPlacement=new InventoryPlacement();
////                updateInventoryPlacement.setStockQty(inventoryPlacement.getStockQty().subtract(new BigDecimal(binIdsVo.getQty())));
////                updateInventoryPlacement.setId(inventoryPlacement.getId());
////                inventoryPlacementMapper.updateById(updateInventoryPlacement);
//            }else {
//                throw new Exception("没有对应库位内码");
//            }
        }

        //查询对应的仓库 -库存  如果没有 添加 有自动添加数量
        for (BinIdsVo binIdsVo : toBinIdsVos) {
            if (ObjectUtils.isEmpty(binIdsVo.getBinId())) {
                if (model.getTo().getValue().equals(TargetTypeVo.Defect)) {
                    binIdsVo.setBinId(getSearchByWarehouseBin(model.getFromStockId(), model.getShopId(), model.getFnSku(), model.getItem().getId(), 2));
                } else {
                    binIdsVo.setBinId(getSearchByWarehouseBin(model.getFromStockId(), model.getShopId(), model.getFnSku(), model.getItem().getId(), 1));
                }
            }
            InventoryPlacementVariation inventoryPlacementVariation = new InventoryPlacementVariation();
            BeanUtils.copyProperties(model, inventoryVariation);
            inventoryPlacementVariation.setChangeType("Exchange");
            inventoryPlacementVariation.setStockId(model.getFromStockId());
            inventoryPlacementVariation.setFromType(model.getFromBinIdsType().getValue());
            inventoryPlacementVariation.setToType(model.getToBinIdsType().getValue());
            inventoryPlacementVariation.setItemId(model.getItem().getId());
            inventoryPlacementVariation.setOperateTime(new Date());
            inventoryPlacementVariation.setBinId(binIdsVo.getBinId());
            inventoryPlacementVariation.setShopId(model.getShopId());
            inventoryPlacementVariation.setFormNum(model.getFormNum());
            inventoryPlacementVariation.setFormOperator(model.getFormOperator());
            inventoryPlacementVariation.setOperateKey(model.getOperateKey());
            inventoryPlacementVariation.setFnSku(model.getFnSku());
            inventoryPlacementVariation.setDocumentType(model.getDocumentType());
//          LambdaQueryWrapper<InventoryPlacement> queryWrapperInventoryPlacementexchangeFromShiftSql= queryWrapperInventoryPlacementexchangeFromShiftSql(model,binIdsVo.getBinId());
//          InventoryPlacement inventoryPlacement= inventoryPlacementMapper.selectOne(queryWrapperInventoryPlacementexchangeFromShiftSql.last(" limit 1"));
            String descOrAsc = queryWrapperInventoryPlacementexchangeFromShiftDescOrAsc(model);
            List<InventoryPlacement> inventoryPlacementList = inventoryPlacementMapper.queryWrapperInventoryPlacementexchangeFromShiftSql(model, binIdsVo.getBinId(), descOrAsc);

            InventoryPlacement inventoryPlacement = new InventoryPlacement();
            if (CollectionUtils.isNotEmpty(inventoryPlacementList)) {
                inventoryPlacement = inventoryPlacementList.get(0);
            } else {
                inventoryPlacement = null;
            }
            if (inventoryPlacement != null) {
                LambdaUpdateChainWrapper<InventoryPlacement> inventoryPlacementUpdateChainWrapper = new LambdaUpdateChainWrapper<>(inventoryPlacementMapper);
                switch (model.getToBinIdsType().getValue()) {
                    case TargetTypeVo.Normal:
                        if (inventoryPlacement.getStockQty() == null) {
                            inventoryPlacement.setStockQty(new BigDecimal(0));
                        }
                        inventoryPlacementVariation.setStockQty(inventoryPlacement.getStockQty().add(new BigDecimal(binIdsVo.getQty())));
                        inventoryPlacementVariation.setChangeStockQty(new BigDecimal(binIdsVo.getQty()));
                        inventoryPlacementUpdateChainWrapper.eq(InventoryPlacement::getId, inventoryPlacement.getId());
                        inventoryPlacementUpdateChainWrapper.eq(InventoryPlacement::getVersion, inventoryPlacement.getVersion());
                        inventoryPlacementUpdateChainWrapper.set(InventoryPlacement::getVersion, inventoryPlacement.getVersion() + 1);
                        inventoryPlacementUpdateChainWrapper.set(InventoryPlacement::getStockQty, inventoryPlacement.getStockQty().add(new BigDecimal(binIdsVo.getQty())));
                        if (!inventoryPlacementUpdateChainWrapper.update()) {
                            throw new Exception("数据版本错误，更新失败");
                        }
                        break;
                    case TargetTypeVo.Lock:
                        if (inventoryPlacement.getLockQty() == null) {
                            inventoryPlacement.setLockQty(new BigDecimal(0));
                        }
                        inventoryPlacementVariation.setLockQty(inventoryPlacement.getLockQty().add(new BigDecimal(binIdsVo.getQty())));
                        inventoryPlacementVariation.setChangeLockQty(new BigDecimal(binIdsVo.getQty()));

                        inventoryPlacementUpdateChainWrapper.eq(InventoryPlacement::getId, inventoryPlacement.getId());
                        inventoryPlacementUpdateChainWrapper.eq(InventoryPlacement::getVersion, inventoryPlacement.getVersion());
                        inventoryPlacementUpdateChainWrapper.set(InventoryPlacement::getVersion, inventoryPlacement.getVersion() + 1);
                        inventoryPlacementUpdateChainWrapper.set(InventoryPlacement::getLockQty, inventoryPlacement.getLockQty().add(new BigDecimal(binIdsVo.getQty())));
                        if (!inventoryPlacementUpdateChainWrapper.update()) {
                            throw new Exception("数据版本错误，更新失败");
                        }
                        break;
                    case TargetTypeVo.Way:
                        if (inventoryPlacement.getWayQty() == null) {
                            inventoryPlacement.setWayQty(new BigDecimal(0));
                        }
                        inventoryPlacementVariation.setWayQty(inventoryPlacement.getWayQty().add(new BigDecimal(binIdsVo.getQty())));
                        inventoryPlacementVariation.setChangeWayQty(new BigDecimal(binIdsVo.getQty()));

                        inventoryPlacementUpdateChainWrapper.eq(InventoryPlacement::getId, inventoryPlacement.getId());
                        inventoryPlacementUpdateChainWrapper.eq(InventoryPlacement::getVersion, inventoryPlacement.getVersion());
                        inventoryPlacementUpdateChainWrapper.set(InventoryPlacement::getVersion, inventoryPlacement.getVersion() + 1);
                        inventoryPlacementUpdateChainWrapper.set(InventoryPlacement::getWayQty, inventoryPlacement.getWayQty().add(new BigDecimal(binIdsVo.getQty())));
                        if (!inventoryPlacementUpdateChainWrapper.update()) {
                            throw new Exception("数据版本错误，更新失败");
                        }
                        break;
                    default:
                        throw new Exception("入库位类型不明确");
                }
                inventoryPlacementVariationMapper.insert(inventoryPlacementVariation);
//                InventoryPlacement updateInventoryPlacement=new InventoryPlacement();
//                updateInventoryPlacement.setStockQty(inventoryPlacement.getStockQty().add(new BigDecimal(binIdsVo.getQty())));
//                updateInventoryPlacement.setId(inventoryPlacement.getId());
//                inventoryPlacementMapper.updateById(updateInventoryPlacement);
            } else {
                //新增
                InventoryPlacement insertInventoryPlacement = new InventoryPlacement();
                BeanUtils.copyProperties(model, insertInventoryPlacement);
                insertInventoryPlacement.setStockId(model.getFromStockId());
                insertInventoryPlacement.setBinId(binIdsVo.getBinId());
                switch (model.getToBinIdsType().getValue()) {
                    case TargetTypeVo.Normal:
                        insertInventoryPlacement.setStockQty(new BigDecimal(binIdsVo.getQty()));
                        inventoryPlacementVariation.setStockQty(new BigDecimal(binIdsVo.getQty()));
                        inventoryPlacementVariation.setChangeStockQty(new BigDecimal(binIdsVo.getQty()));
                        break;
                    case TargetTypeVo.Lock:
                        insertInventoryPlacement.setLockQty(new BigDecimal(binIdsVo.getQty()));
                        inventoryPlacementVariation.setLockQty(new BigDecimal(binIdsVo.getQty()));
                        inventoryPlacementVariation.setChangeLockQty(new BigDecimal(binIdsVo.getQty()));
                        break;
                    case TargetTypeVo.Way:
                        inventoryPlacementVariation.setWayQty(new BigDecimal(binIdsVo.getQty()));
                        inventoryPlacementVariation.setChangeWayQty(new BigDecimal(binIdsVo.getQty()));
                        insertInventoryPlacement.setWayQty(new BigDecimal(binIdsVo.getQty()));
                        break;
                    default:
                        throw new Exception("入库位类型不明确");
                }
                if (inventory != null) {
                    insertInventoryPlacement.setAuxId(inventory.getAuxId());
                    insertInventoryPlacement.setAuxQty(inventory.getAuxQty());
                    insertInventoryPlacement.setProductionDate(inventory.getProductionDate());
                    insertInventoryPlacement.setExpiryDate(inventory.getExpiryDate());
                    insertInventoryPlacement.setShelfLife(inventory.getShelfLife());
                }
                insertInventoryPlacement.setItemId(model.getItem().getId());
                if (StringUtils.isBlank(model.getBatchNo())) {
                    insertInventoryPlacement.setBatchNo(null);
                }
                inventoryPlacementMapper.insert(insertInventoryPlacement);
                inventoryPlacementVariationMapper.insert(inventoryPlacementVariation);
            }
        }
//        inventoryVariationMapper.insert(inventoryVariation);
//        List<Long> variationIds=new ArrayList<>();
//        variationIds.add(inventoryVariation.getId());
//        inventoryListReturnVo.setVariationIds(variationIds);
        return inventoryListReturnVo;
    }

    private LambdaQueryWrapper<InventoryBatchNo> queryWrapperInventoryexchangeSqlBatchNo(InventoryExchangeVo model) throws Exception {
        //过滤 条件 null也过滤
        LambdaQueryWrapper<InventoryBatchNo> queryWrapper = new LambdaQueryWrapper<>();
        if (model.getFromStockId() == null) {
            queryWrapper.isNull(InventoryBatchNo::getStockId);
        } else {
            queryWrapper.eq(InventoryBatchNo::getStockId, model.getFromStockId());
        }
        if (model.getProjectId() == null) {
            queryWrapper.isNull(InventoryBatchNo::getProjectId);
        } else {
            queryWrapper.eq(InventoryBatchNo::getProjectId, model.getProjectId());
        }
        if (model.getItem().getId() == null) {
            queryWrapper.isNull(InventoryBatchNo::getItemId);
        } else {
            queryWrapper.eq(InventoryBatchNo::getItemId, model.getItem().getId());
        }
//        if (StringUtils.isNotBlank(model.getBatchNo())) {
//            queryWrapper.eq(InventoryBatchNo::getBatchNo, model.getBatchNo());
//        } else {
//            queryWrapper.isNull(InventoryBatchNo::getBatchNo);
//        }
        if (StringUtils.isNotBlank(model.getFnSku())) {
            queryWrapper.eq(InventoryBatchNo::getFnSku, model.getFnSku());
        } else {
            queryWrapper.isNull(InventoryBatchNo::getFnSku);
        }
        if (StringUtils.isNotBlank(model.getShopId())) {
            queryWrapper.eq(InventoryBatchNo::getShopId, model.getShopId());
        } else {
            queryWrapper.isNull(InventoryBatchNo::getShopId);

        }

        switch (model.getModel().getValue()) {
            case PatternVo.FIFO:
                queryWrapper.orderByAsc(InventoryBatchNo::getCreateTime);
                break;
            case PatternVo.LIFO:
                queryWrapper.orderByDesc(InventoryBatchNo::getCreateTime);
                break;
            case PatternVo.ExpiryEarlier:
                //近有效期先出"不新鲜" ？？
                queryWrapper.orderByAsc(InventoryBatchNo::getExpiryDate);
                break;
            case PatternVo.ExpiryLater:
                queryWrapper.orderByDesc(InventoryBatchNo::getExpiryDate);
                break;
            default:
                throw new Exception("对应模式不符合");
        }

        return queryWrapper;

    }

    /**
     * @param model
     * @return
     */
    private LambdaQueryWrapper<Inventory> queryWrapperInventoryexchangeSql(InventoryExchangeVo model) throws Exception {
        //过滤 条件 null也过滤
        LambdaQueryWrapper<Inventory> queryWrapper = new LambdaQueryWrapper<>();
        if (model.getFromStockId() == null) {
            queryWrapper.isNull(Inventory::getStockId);
        } else {
            queryWrapper.eq(Inventory::getStockId, model.getFromStockId());
        }
        if (model.getProjectId() == null) {
            queryWrapper.isNull(Inventory::getProjectId);
        } else {
            queryWrapper.eq(Inventory::getProjectId, model.getProjectId());
        }
        if (model.getItem().getId() == null) {
            queryWrapper.isNull(Inventory::getItemId);
        } else {
            queryWrapper.eq(Inventory::getItemId, model.getItem().getId());
        }
//        if (StringUtils.isNotBlank(model.getBatchNo())) {
//            queryWrapper.eq(Inventory::getBatchNo, model.getBatchNo());
//        } else {
//            queryWrapper.isNull(Inventory::getBatchNo);
//        }
        if (StringUtils.isNotBlank(model.getFnSku())) {
            queryWrapper.eq(Inventory::getFnSku, model.getFnSku());
        } else {
            queryWrapper.isNull(Inventory::getFnSku);
        }
        if (StringUtils.isNotBlank(model.getShopId())) {
            queryWrapper.eq(Inventory::getShopId, model.getShopId());
        } else {
            queryWrapper.isNull(Inventory::getShopId);
        }

        switch (model.getModel().getValue()) {
            case PatternVo.FIFO:
                queryWrapper.orderByAsc(Inventory::getExpiryDate);
                break;
            case PatternVo.LIFO:
                queryWrapper.orderByDesc(Inventory::getExpiryDate);
                break;
            case PatternVo.ExpiryEarlier:
                //近有效期先出"不新鲜" ？？
                queryWrapper.orderByAsc(Inventory::getExpiryDate);
                break;
            case PatternVo.ExpiryLater:
                queryWrapper.orderByDesc(Inventory::getExpiryDate);
                break;
            default:
                throw new Exception("对应模式不符合");
        }

        return queryWrapper;

    }

    private LambdaQueryWrapper<InventoryPlacement> queryWrapperInventoryPlacementexchangeFromShiftSql(InventoryExchangeVo model, Integer binId) throws Exception {
        //过滤 条件 null也过滤
        LambdaQueryWrapper<InventoryPlacement> queryWrapper = new LambdaQueryWrapper<>();
        if (binId == null) {
            queryWrapper.isNull(InventoryPlacement::getBinId);
        } else {
            queryWrapper.eq(InventoryPlacement::getBinId, binId);
        }
        if (model.getFromStockId() == null) {
            queryWrapper.isNull(InventoryPlacement::getStockId);
        } else {
            queryWrapper.eq(InventoryPlacement::getStockId, model.getFromStockId());
        }
        if (model.getProjectId() == null) {
            queryWrapper.isNull(InventoryPlacement::getProjectId);
        } else {
            queryWrapper.eq(InventoryPlacement::getProjectId, model.getProjectId());
        }
        if (model.getItem().getId() == null) {
            queryWrapper.isNull(InventoryPlacement::getItemId);
        } else {
            queryWrapper.eq(InventoryPlacement::getItemId, model.getItem().getId());
        }
        if (StringUtils.isNotBlank(model.getBatchNo())) {
            queryWrapper.eq(InventoryPlacement::getBatchNo, model.getBatchNo());
        } else {
            queryWrapper.isNull(InventoryPlacement::getBatchNo);
        }
        switch (model.getModel().getValue()) {
            case PatternVo.FIFO:
                queryWrapper.orderByAsc(InventoryPlacement::getExpiryDate);
                break;
            case PatternVo.LIFO:
                queryWrapper.orderByDesc(InventoryPlacement::getExpiryDate);
                break;
            case PatternVo.ExpiryEarlier:
                //近有效期先出"不新鲜" ？？
                queryWrapper.orderByAsc(InventoryPlacement::getExpiryDate);
                break;
            case PatternVo.ExpiryLater:
                queryWrapper.orderByDesc(InventoryPlacement::getExpiryDate);
                break;
            default:
                throw new Exception("对应模式不符合");
        }
        return queryWrapper;
    }

    private String queryWrapperInventoryPlacementexchangeFromShiftDescOrAsc(InventoryExchangeVo model) throws Exception {
        String descOrAsc = "";
        switch (model.getModel().getValue()) {
            case PatternVo.FIFO:
                descOrAsc = "asc";
                break;
            case PatternVo.LIFO:
                descOrAsc = "desc";
                break;
            case PatternVo.ExpiryEarlier:
                //近有效期先出"不新鲜" ？？
                descOrAsc = "asc";
                break;
            case PatternVo.ExpiryLater:
                descOrAsc = "desc";
                break;
            default:
                throw new Exception("对应模式不符合");
        }
        return descOrAsc;
    }

    private void verificationExchange(InventoryExchangeVo model) throws Exception {
        if (null == model.getFromStockId()) {
            throw new Exception("fromStockId 为空");
        }
        if (null == model.getToStockId()) {
            throw new Exception("toStockId 为空");
        }
        if (ObjectUtils.allNull(model.getItem())) {
            throw new Exception("item 为空");
        }
        if (QtyIsZeroConfig.isOpen) {
            if (model.getQty() == null) {
                throw new Exception("操作数量不能为空");
            }
        } else if (model.getQty() == null || BigDecimal.ZERO.equals(model.getQty())) {
            throw new Exception("操作数量不能为空或零");
        }
        if (!BooleanUtil.isTrue(model.getSupportNegative()) && model.getQty().compareTo(BigDecimal.ZERO) < 0) {
            throw new Exception("操作数量不能为负数");
        }
    }

    /**
     * @param model 出库
     * @return
     */
    @Transactional(rollbackFor = Exception.class)
    @Override
    public synchronized InventoryListReturnVo outboundItem(InventoryOutboundVo model) throws Exception {
        getDocumentType(model.getDocumentType());
        InventoryListReturnVo inventoryListReturnVo = new InventoryListReturnVo();
        if (model.getQty().compareTo(BigDecimal.ZERO) == 0) {
            return inventoryListReturnVo;
        }
        List<BinIdsVo> binIdsVos = new ArrayList<>();
        verificationOutbound(model);
        if (null != model.getBinIds()) {
            binIdsVos = model.getBinIds().entrySet().stream().map(c -> new BinIdsVo(c.getKey(), c.getValue())).collect(Collectors.toList());
            long sum = binIdsVos.stream().mapToLong(BinIdsVo::getQty).sum();
            if (QtyIsZeroConfig.isOpen) {
                if (model.getQty().compareTo(BigDecimal.ZERO) == 0) {
                    return inventoryListReturnVo;
                }
                if (model.getQty().longValue() != sum) {
                    throw new Exception("bindIds 为非空时，所有入位数量合计不等于qty");
                }
            } else if (sum <= 0 || model.getQty().longValue() != sum) {
                throw new Exception("bindIds为非空时，所有入位数量大于0并且合计不等于qty");
            }
        }
        String descOrAsc = queryWrapperInventoryOutboundDescOrAsc(model);
        // 是否开启库龄 只做库龄 表得减  库位 还按原来来的处理
        if (StockAgeConfig.isOpen) {
            List<InventoryBatchNo> list = inventoryBatchNoMapper.selectByOutboundList(model, model.getModel().getValue());
            if (CollectionUtils.isEmpty(list)) {
                // 是否开启负库存 如果开启
                if (getIsOpenNegativeInventory(model.getStockId())) {
                    throw new Exception(getItemIdName(model.getItem().getId()) + " 没有查到对应批次库存表数据");
                } else {
                    //添加新的 在处理
                    InventoryStorageVo inventoryStorageVo = new InventoryStorageVo();
                    BeanUtils.copyProperties(model, inventoryStorageVo);
                    inventoryStorageVo.setQty(BigDecimal.valueOf(0));
                    inventoryStorageVo.setTo(model.getFrom());
                    storageAgeInsert(inventoryStorageVo, inventoryListReturnVo, binIdsVos);
                    list = inventoryBatchNoMapper.selectByOutboundList(model, model.getModel().getValue());
                }

            }
            // 是否开启负库存
            if (getIsOpenNegativeInventory(model.getStockId())) {
                verificationOutboundInventoryBatchNo(model, list); //库龄验证
            }
            outboundUpdateBatchNo(model, list, binIdsVos);
        }
        List<Inventory> inventoryList = inventoryMapper.selectByOutboundList(model, model.getModel().getValue());
        if (CollectionUtils.isEmpty(inventoryList)) {
            // 是否开启负库存 如果开启
            if (getIsOpenNegativeInventory(model.getStockId())) {
                throw new Exception(getItemIdName(model.getItem().getId()) + "没有查到对应库存表数据");
            } else {
                //添加新的 在处理
                InventoryStorageVo inventoryStorageVo = new InventoryStorageVo();
                BeanUtils.copyProperties(model, inventoryStorageVo);
                inventoryStorageVo.setQty(BigDecimal.valueOf(0));
                inventoryStorageVo.setTo(model.getFrom());
                storageInsert(inventoryStorageVo, inventoryListReturnVo, binIdsVos);
                inventoryList = inventoryMapper.selectByOutboundList(model, model.getModel().getValue());
            }

        }
        // 是否开启负库存
        if (getIsOpenNegativeInventory(model.getStockId())) {
            //校验库存是否满足
            verificationOutboundInventory(model, inventoryList);  //库存验证 todo 可合并 库龄验证
        }
        return outboundUpdate(model, inventoryList, binIdsVos);

    }

    private InventoryListReturnVo outboundUpdateBatchNo(InventoryOutboundVo model, List<InventoryBatchNo> list, List<BinIdsVo> binIdsVos) throws Exception {
        InventoryListReturnVo inventoryListReturnVo = new InventoryListReturnVo();
        // 要处理的量
        BigDecimal qtySum = model.getQty();
        List<Long> updateIds = new ArrayList<>();
        List<Long> delIds = new ArrayList<>();
        List<Long> variationIds = new ArrayList<>();
        for (InventoryBatchNo inventory : list) {
            if (qtySum.compareTo(BigDecimal.ZERO) == 0) {
                //库存都处理完
                break;
            }
            updateIds.add(inventory.getId());
            InventoryVariation inventoryVariation = new InventoryVariation();
            LambdaUpdateChainWrapper<InventoryBatchNo> inventoryUpdateChainWrapper = new LambdaUpdateChainWrapper<>(inventoryBatchNoMapper);

            inventoryUpdateChainWrapper.eq(InventoryBatchNo::getId, inventory.getId());
            inventoryUpdateChainWrapper.eq(InventoryBatchNo::getVersion, inventory.getVersion());
            inventoryUpdateChainWrapper.set(InventoryBatchNo::getVersion, inventory.getVersion() + 1);

            Inventory updateInventory = new Inventory();
            updateInventory.setId(inventory.getId());
            BeanUtils.copyProperties(model, inventoryVariation);
            inventoryVariation.setChangeType("Out");
            inventoryVariation.setFromType(model.getFrom().getValue());
            inventoryVariation.setItemId(model.getItem().getId());
            inventoryVariation.setOperateTime(new Date());
            inventoryVariation.setStockQty(inventory.getStockQty());
            inventoryVariation.setLockQty(inventory.getLockQty());
            inventoryVariation.setDisplayQty(inventory.getDisplayQty());
            inventoryVariation.setDefectQty(inventory.getDefectQty());
            inventoryVariation.setWayQty(inventory.getWayQty());
            inventoryVariation.setStorageQty(inventory.getStorageQty());
            inventoryVariation.setRejectLockQty(inventory.getRejectLockQty());
            inventoryVariation.setRejectWayQty(inventory.getRejectWayQty());
            inventoryVariation.setInspectedQty(inventory.getInspectedQty());

            BigDecimal stockQty = orZero(inventory.getStockQty());
            BigDecimal lockQty = orZero(inventory.getLockQty());
            BigDecimal detDefectQty = orZero(inventory.getDefectQty());
            BigDecimal wayQty = orZero(inventory.getWayQty());
            BigDecimal displayQty = orZero(inventory.getDisplayQty());
            BigDecimal normalQty = stockQty.subtract(lockQty).subtract(detDefectQty).subtract(displayQty);
            BigDecimal storageQty = orZero(inventory.getStorageQty());
            BigDecimal rejectLockQty = orZero(inventory.getRejectLockQty());
            BigDecimal rejectWayQty = orZero(inventory.getRejectWayQty());
            BigDecimal inspectedQty = orZero(inventory.getInspectedQty());
            BigDecimal pickingQty = orZero(inventory.getPickingQty());

            switch (model.getFrom().getValue()) {
                case TargetTypeVo.Normal:
                    if (!getIsOpenNegativeInventory(model.getStockId())) {
                        updateInventory.setStockQty(stockQty.subtract(qtySum));
                        inventoryVariation.setStockQty(updateInventory.getStockQty());
                        inventoryVariation.setChangeStockQty(qtySum.negate());
                        qtySum = BigDecimal.ZERO;
                    } else if (normalQty.compareTo(qtySum) >= 0) {
                        updateInventory.setStockQty(stockQty.subtract(qtySum));
                        inventoryVariation.setStockQty(updateInventory.getStockQty());
                        inventoryVariation.setChangeStockQty(qtySum.negate());
                        qtySum = BigDecimal.ZERO;
                    } else {
                        updateInventory.setStockQty(stockQty.subtract(normalQty));
                        inventoryVariation.setStockQty(updateInventory.getStockQty());
                        inventoryVariation.setChangeStockQty(updateInventory.getStockQty().negate());
                        qtySum = qtySum.subtract(normalQty);
                    }
                    // updateInventory.setStockQty(inventoryVariation.getStockQty());
                    inventoryUpdateChainWrapper.set(InventoryBatchNo::getStockQty, updateInventory.getStockQty());
                    if (!inventoryUpdateChainWrapper.update()) {
                        throw new Exception("数据版本错误，更新失败");
                    }

                    break;
                case TargetTypeVo.Lock:
                    if (!getIsOpenNegativeInventory(model.getStockId())) {
                        updateInventory.setStockQty(stockQty.subtract(qtySum));
                        updateInventory.setLockQty(lockQty.subtract(qtySum));
                        inventoryVariation.setStockQty(updateInventory.getStockQty());
                        inventoryVariation.setLockQty(updateInventory.getLockQty());
                        inventoryVariation.setChangeLockQty(qtySum.negate());
                        inventoryVariation.setChangeStockQty(qtySum.negate());
                        qtySum = BigDecimal.ZERO;
                    } else if (lockQty.compareTo(qtySum) >= 0) {
                        updateInventory.setStockQty(stockQty.subtract(qtySum));
                        updateInventory.setLockQty(lockQty.subtract(qtySum));
                        inventoryVariation.setStockQty(updateInventory.getStockQty());
                        inventoryVariation.setLockQty(updateInventory.getLockQty());
                        inventoryVariation.setChangeLockQty(qtySum.negate());
                        inventoryVariation.setChangeStockQty(qtySum.negate());
                        qtySum = BigDecimal.ZERO;
                    } else {
                        updateInventory.setStockQty(stockQty.subtract(lockQty));
                        updateInventory.setLockQty(BigDecimal.ZERO);
                        inventoryVariation.setLockQty(updateInventory.getLockQty());
                        inventoryVariation.setStockQty(updateInventory.getStockQty());
                        inventoryVariation.setChangeLockQty(lockQty.negate());
                        inventoryVariation.setChangeStockQty(lockQty.negate());
                        qtySum = qtySum.subtract(lockQty);
                    }

                    inventoryUpdateChainWrapper.set(InventoryBatchNo::getStockQty, updateInventory.getStockQty());
                    inventoryUpdateChainWrapper.set(InventoryBatchNo::getLockQty, updateInventory.getLockQty());
                    if (!inventoryUpdateChainWrapper.update()) {
                        throw new Exception("数据版本错误，更新失败");
                    }

                    break;
                case TargetTypeVo.Display:

                    if (!getIsOpenNegativeInventory(model.getStockId())) {
                        updateInventory.setStockQty(stockQty.subtract(qtySum));
                        updateInventory.setDisplayQty(displayQty.subtract(qtySum));
                        inventoryVariation.setDisplayQty(updateInventory.getDisplayQty());
                        inventoryVariation.setStockQty(updateInventory.getStockQty());
                        inventoryVariation.setChangeDisplayQty(qtySum.negate());
                        inventoryVariation.setChangeStockQty(qtySum.negate());
                        qtySum = BigDecimal.ZERO;
                    } else if (displayQty.compareTo(qtySum) >= 0) {
                        updateInventory.setStockQty(stockQty.subtract(qtySum));
                        updateInventory.setDisplayQty(displayQty.subtract(qtySum));
                        inventoryVariation.setDisplayQty(updateInventory.getDisplayQty());
                        inventoryVariation.setStockQty(updateInventory.getStockQty());
                        inventoryVariation.setChangeDisplayQty(qtySum.negate());
                        inventoryVariation.setChangeStockQty(qtySum.negate());
                        qtySum = BigDecimal.ZERO;
                    } else {
                        updateInventory.setLockQty(BigDecimal.ZERO);
                        updateInventory.setStockQty(stockQty.subtract(displayQty));
                        inventoryVariation.setLockQty(updateInventory.getLockQty());
                        inventoryVariation.setStockQty(updateInventory.getStockQty());
                        inventoryVariation.setChangeLockQty(displayQty.negate());
                        inventoryVariation.setChangeStockQty(displayQty.negate());
                        qtySum = qtySum.subtract(displayQty);
                    }


                    inventoryUpdateChainWrapper.set(InventoryBatchNo::getDisplayQty, updateInventory.getDisplayQty());
                    if (!inventoryUpdateChainWrapper.update()) {
                        throw new Exception("数据版本错误，更新失败");
                    }

                    break;
                case TargetTypeVo.Defect:
//                    if(detDefectQty.compareTo(model.getQty())==-1){
//                        throw new Exception("出库数量大于残次数量");
//                    }
                    if (!getIsOpenNegativeInventory(model.getStockId())) {
                        updateInventory.setStockQty(stockQty.subtract(qtySum));
                        updateInventory.setDefectQty(detDefectQty.subtract(qtySum));
                        inventoryVariation.setStockQty(updateInventory.getStockQty());
                        inventoryVariation.setDefectQty(updateInventory.getDefectQty());
                        inventoryVariation.setChangeStockQty(qtySum.negate());
                        inventoryVariation.setChangeDefectQty(qtySum.negate());
                        qtySum = BigDecimal.ZERO;
                    } else if (detDefectQty.compareTo(qtySum) >= 0) {
                        updateInventory.setStockQty(stockQty.subtract(qtySum));
                        updateInventory.setDefectQty(detDefectQty.subtract(qtySum));
                        inventoryVariation.setStockQty(updateInventory.getStockQty());
                        inventoryVariation.setDefectQty(updateInventory.getDefectQty());
                        inventoryVariation.setChangeStockQty(qtySum.negate());
                        inventoryVariation.setChangeDefectQty(qtySum.negate());
                        qtySum = BigDecimal.ZERO;
                    } else {
                        updateInventory.setStockQty(stockQty.subtract(detDefectQty));
                        updateInventory.setDefectQty(BigDecimal.ZERO);
                        inventoryVariation.setStockQty(updateInventory.getStockQty());
                        inventoryVariation.setDefectQty(updateInventory.getDefectQty());
                        inventoryVariation.setChangeStockQty(detDefectQty.negate());
                        inventoryVariation.setDefectQty(detDefectQty.negate());
                        qtySum = qtySum.subtract(detDefectQty);
                    }
//                    inventoryVariation.setDefectQty(model.getQty());
//                    updateInventory.setStockQty(stockQty.subtract(model.getQty()));
//                    updateInventory.setDefectQty(lockQty.subtract(model.getQty()));
                    inventoryUpdateChainWrapper.set(InventoryBatchNo::getStockQty, updateInventory.getStockQty());
                    inventoryUpdateChainWrapper.set(InventoryBatchNo::getDefectQty, updateInventory.getDefectQty());
                    if (!inventoryUpdateChainWrapper.update()) {
                        throw new Exception("数据版本错误，更新失败");
                    }
                    //this.updateById(updateInventory);
//                    if (isZero(updateInventory.getStockQty(), lockQty, updateInventory.getDefectQty(), wayQty, displayQty)) {
//                        this.removeById(updateInventory.getId());
//                        delIds.add(updateInventory.getId());
//                    }
                    break;
                case TargetTypeVo.Way:
//                    if (wayQty.compareTo(model.getQty()) == -1) {
//                        throw new Exception("出库数量大于在途数量");
//                    }
                    if (!getIsOpenNegativeInventory(model.getStockId())) {
                        updateInventory.setWayQty(wayQty.subtract(qtySum));
                        inventoryVariation.setWayQty(updateInventory.getWayQty());
                        inventoryVariation.setChangeWayQty(qtySum.negate());
                        qtySum = BigDecimal.ZERO;
                    } else if (wayQty.compareTo(qtySum) >= 0) {
                        updateInventory.setWayQty(wayQty.subtract(qtySum));
                        inventoryVariation.setWayQty(updateInventory.getWayQty());
                        inventoryVariation.setChangeWayQty(qtySum.negate());
                        qtySum = BigDecimal.ZERO;
                    } else {
                        updateInventory.setWayQty(BigDecimal.ZERO);
                        inventoryVariation.setWayQty(updateInventory.getWayQty());
                        inventoryVariation.setChangeWayQty(wayQty.negate());
                        qtySum = qtySum.subtract(wayQty);
                    }
                    // inventoryVariation.setWayQty(model.getQty());
                    //  updateInventory.setWayQty(wayQty.subtract(model.getQty()));
                    inventoryUpdateChainWrapper.set(InventoryBatchNo::getWayQty, updateInventory.getWayQty());
                    if (!inventoryUpdateChainWrapper.update()) {
                        throw new Exception("数据版本错误，更新失败");
                    }
                    //this.updateById(updateInventory);
//                    if (isZero(stockQty, lockQty, detDefectQty, updateInventory.getWayQty(), displayQty)) {
//                        this.removeById(updateInventory.getId());
//                        delIds.add(updateInventory.getId());
//                    }
                    break;
                case TargetTypeVo.Storage:
                    if (!getIsOpenNegativeInventory(model.getStockId()) || storageQty.compareTo(qtySum) >= 0) { //开启负库存 || 暂存数量够
                        updateInventory.setStorageQty(storageQty.subtract(qtySum));
                        inventoryVariation.setStorageQty(updateInventory.getStorageQty());
                        inventoryVariation.setChangeStorageQty(qtySum.negate());
                        qtySum = BigDecimal.ZERO;
                    } else if (NumberUtil.isGreater(NumberUtil.add(normalQty, storageQty), qtySum)) {   //暂存 + 可用够
                        updateInventory.setStorageQty(BigDecimal.ZERO);
                        updateInventory.setStockQty(stockQty.subtract(qtySum.subtract(storageQty))); //剩余可用(锁定 + 陈列 + 残次) = 总可用 - 可用
                        inventoryVariation.setStorageQty(BigDecimal.ZERO);
                        inventoryVariation.setStockQty(stockQty.subtract(qtySum.subtract(storageQty)));
                        inventoryVariation.setChangeStorageQty(storageQty.negate());
                        inventoryVariation.setChangeStockQty(qtySum.subtract(storageQty).negate());
                        qtySum = BigDecimal.ZERO;
                    } else {   //暂存 + 可用不够:扣完
                        updateInventory.setStorageQty(BigDecimal.ZERO);
                        updateInventory.setStockQty(NumberUtil.sub(stockQty, normalQty)); //剩余可用(锁定 + 陈列 + 残次) = 总可用 - 可用
                        inventoryVariation.setStorageQty(BigDecimal.ZERO);
                        inventoryVariation.setStockQty(NumberUtil.sub(stockQty, normalQty));
                        inventoryVariation.setChangeStorageQty(storageQty.negate());
                        inventoryVariation.setChangeStockQty(normalQty.negate());
                        qtySum = qtySum.subtract(NumberUtil.add(normalQty, storageQty));
                    }
                    inventoryUpdateChainWrapper.set(InventoryBatchNo::getStorageQty, updateInventory.getStorageQty());
                    if (!inventoryUpdateChainWrapper.update()) {
                        throw new Exception("数据版本错误，更新失败");
                    }
                    break;
                case TargetTypeVo.RejectLock:
                    if (!getIsOpenNegativeInventory(model.getStockId())) {
                        updateInventory.setRejectLockQty(rejectLockQty.subtract(qtySum));
                        inventoryVariation.setRejectLockQty(updateInventory.getRejectLockQty());
                        inventoryVariation.setChangeRejectLockQty(qtySum.negate());
                        qtySum = BigDecimal.ZERO;
                    } else if (rejectLockQty.compareTo(qtySum) >= 0) {
                        updateInventory.setRejectLockQty(rejectLockQty.subtract(qtySum));
                        inventoryVariation.setRejectLockQty(updateInventory.getRejectLockQty());
                        inventoryVariation.setChangeRejectLockQty(qtySum.negate());
                        qtySum = BigDecimal.ZERO;
                    } else {
                        updateInventory.setRejectLockQty(BigDecimal.ZERO);
                        inventoryVariation.setRejectLockQty(updateInventory.getRejectLockQty());
                        inventoryVariation.setChangeRejectLockQty(rejectLockQty.negate());
                        qtySum = qtySum.subtract(rejectLockQty);
                    }
                    inventoryUpdateChainWrapper.set(InventoryBatchNo::getRejectLockQty, updateInventory.getRejectLockQty());
                    if (!inventoryUpdateChainWrapper.update()) {
                        throw new Exception("数据版本错误，更新失败");
                    }
                    break;
                case TargetTypeVo.RejectWay:
                    if (!getIsOpenNegativeInventory(model.getStockId())) {
                        updateInventory.setRejectWayQty(rejectWayQty.subtract(qtySum));
                        inventoryVariation.setRejectWayQty(updateInventory.getRejectWayQty());
                        inventoryVariation.setChangeRejectWayQty(qtySum.negate());
                        qtySum = BigDecimal.ZERO;
                    } else if (rejectWayQty.compareTo(qtySum) >= 0) {
                        updateInventory.setRejectWayQty(rejectWayQty.subtract(qtySum));
                        inventoryVariation.setRejectWayQty(updateInventory.getRejectWayQty());
                        inventoryVariation.setChangeRejectWayQty(qtySum.negate());
                        qtySum = BigDecimal.ZERO;
                    } else {
                        updateInventory.setRejectWayQty(BigDecimal.ZERO);
                        inventoryVariation.setRejectWayQty(updateInventory.getRejectWayQty());
                        inventoryVariation.setChangeRejectWayQty(rejectWayQty.negate());
                        qtySum = qtySum.subtract(rejectWayQty);
                    }
                    inventoryUpdateChainWrapper.set(InventoryBatchNo::getRejectWayQty, updateInventory.getRejectWayQty());
                    if (!inventoryUpdateChainWrapper.update()) {
                        throw new Exception("数据版本错误，更新失败");
                    }
                    break;
                case TargetTypeVo.Inspected:
                    if (!getIsOpenNegativeInventory(model.getStockId())) {
                        updateInventory.setInspectedQty(inspectedQty.subtract(qtySum));
                        inventoryVariation.setInspectedQty(updateInventory.getInspectedQty());
                        inventoryVariation.setChangeInspectedQty(qtySum.negate());
                        qtySum = BigDecimal.ZERO;
                    } else if (inspectedQty.compareTo(qtySum) >= 0) {
                        updateInventory.setInspectedQty(inspectedQty.subtract(qtySum));
                        inventoryVariation.setInspectedQty(updateInventory.getInspectedQty());
                        inventoryVariation.setChangeInspectedQty(qtySum.negate());
                        qtySum = BigDecimal.ZERO;
                    } else {
                        updateInventory.setInspectedQty(BigDecimal.ZERO);
                        inventoryVariation.setInspectedQty(updateInventory.getInspectedQty());
                        inventoryVariation.setChangeInspectedQty(inspectedQty.negate());
                        qtySum = qtySum.subtract(inspectedQty);
                    }
                    inventoryUpdateChainWrapper.set(InventoryBatchNo::getInspectedQty, updateInventory.getInspectedQty());
                    if (!inventoryUpdateChainWrapper.update()) {
                        throw new Exception("数据版本错误，更新失败");
                    }
                    break;
                case TargetTypeVo.Picking:
                    if (!getIsOpenNegativeInventory(model.getStockId())) {
                        updateInventory.setPickingQty(pickingQty.subtract(qtySum));
                        inventoryVariation.setPickingQty(updateInventory.getPickingQty());
                        inventoryVariation.setChangePickingQty(qtySum.negate());
                        qtySum = BigDecimal.ZERO;
                    } else if (pickingQty.compareTo(qtySum) >= 0) {
                        updateInventory.setPickingQty(pickingQty.subtract(qtySum));
                        inventoryVariation.setPickingQty(updateInventory.getPickingQty());
                        inventoryVariation.setChangePickingQty(qtySum.negate());
                        qtySum = BigDecimal.ZERO;
                    } else {
                        updateInventory.setPickingQty(BigDecimal.ZERO);
                        inventoryVariation.setPickingQty(updateInventory.getPickingQty());
                        inventoryVariation.setChangePickingQty(pickingQty.negate());
                        qtySum = qtySum.subtract(pickingQty);
                    }
                    inventoryUpdateChainWrapper.set(InventoryBatchNo::getPickingQty, updateInventory.getPickingQty());
                    if (!inventoryUpdateChainWrapper.update()) {
                        throw new Exception("数据版本错误，更新失败");
                    }
                    break;
                default:
                    throw new Exception("出库源类型不明确");
            }

            variationIds.add(inventoryVariation.getId());

        }
        inventoryListReturnVo.setUpdateIds(updateIds);
        inventoryListReturnVo.setRemoveIds(delIds);
        inventoryListReturnVo.setVariationIds(variationIds);
        return inventoryListReturnVo;
    }

    private void verificationOutboundInventoryBatchNo(InventoryOutboundVo model, List<InventoryBatchNo> inventoryList) throws Exception {
        //校验库存是否有那么多
        BigDecimal stockQty = inventoryList.stream().filter(c -> c.getStockQty() != null).map(InventoryBatchNo::getStockQty).reduce(BigDecimal.ZERO, BigDecimal::add);
        BigDecimal lockQty = inventoryList.stream().filter(c -> c.getLockQty() != null).map(InventoryBatchNo::getLockQty).reduce(BigDecimal.ZERO, BigDecimal::add);
        BigDecimal detDefectQty = inventoryList.stream().filter(c -> c.getDefectQty() != null).map(InventoryBatchNo::getDefectQty).reduce(BigDecimal.ZERO, BigDecimal::add);
        BigDecimal displayQty = inventoryList.stream().filter(c -> c.getDisplayQty() != null).map(InventoryBatchNo::getDisplayQty).reduce(BigDecimal.ZERO, BigDecimal::add);
        BigDecimal wayQty = inventoryList.stream().filter(c -> c.getWayQty() != null).map(InventoryBatchNo::getWayQty).reduce(BigDecimal.ZERO, BigDecimal::add);
        BigDecimal storageQty = inventoryList.stream().filter(c -> c.getStorageQty() != null).map(InventoryBatchNo::getStorageQty).reduce(BigDecimal.ZERO, BigDecimal::add);
        BigDecimal rejectLockQty = inventoryList.stream().filter(c -> c.getRejectLockQty() != null).map(InventoryBatchNo::getRejectLockQty).reduce(BigDecimal.ZERO, BigDecimal::add);
        BigDecimal rejectWayQty = inventoryList.stream().filter(c -> c.getRejectWayQty() != null).map(InventoryBatchNo::getRejectWayQty).reduce(BigDecimal.ZERO, BigDecimal::add);
        BigDecimal inspectedQty = inventoryList.stream().filter(c -> c.getInspectedQty() != null).map(InventoryBatchNo::getInspectedQty).reduce(BigDecimal.ZERO, BigDecimal::add);
        BigDecimal pickingQty = inventoryList.stream().filter(c -> c.getPickingQty() != null).map(InventoryBatchNo::getPickingQty).reduce(BigDecimal.ZERO, BigDecimal::add);

        //可用 = 可用 -对应的锁库 - 残次 - 陈列 不能大于当前的库存
        stockQty = stockQty.subtract(lockQty.add(detDefectQty).add(displayQty));
        //暂存 = 暂存 + 可用
        storageQty = NumberUtil.add(storageQty, stockQty);
        String itemIdName = "";
        if (StringUtils.isNotBlank(MaterialConfig.sql)) {
            try {
                String sql = String.format(MaterialConfig.sql, model.getItem().getId());
                itemIdName = inventoryMapper.selectMaterial(sql);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        switch (model.getFrom().getValue()) {
            case TargetTypeVo.Normal:
                if (stockQty.compareTo(model.getQty()) < 0) {
                    // throw new InventoryException(model.getItem().getId(), itemIdName+" 出库数量大于库存数量-锁库数量-残次数量 库存数："+stockQty.subtract(lockQty.add(detDefectQty)));
                    throw new InventoryException(model.getItem().getId(), itemIdName + "  库存不足：" + model.getQty().subtract(stockQty));
                }
                break;
            case TargetTypeVo.Lock:
                if (lockQty.compareTo(model.getQty()) < 0) {
                    throw new InventoryException(model.getItem().getId(), itemIdName + " 锁库库存不足：" + model.getQty().subtract(lockQty));
                }
                break;
            case TargetTypeVo.Display:
                if (displayQty.compareTo(model.getQty()) < 0) {
                    throw new InventoryException(model.getItem().getId(), itemIdName + " 展品库存不足：" + model.getQty().subtract(displayQty));
                }
                break;
            case TargetTypeVo.Defect:
                if (detDefectQty.compareTo(model.getQty()) < 0) {
                    throw new InventoryException(model.getItem().getId(), itemIdName + " 残次库存不足：" + model.getQty().subtract(detDefectQty));
                }
                break;
            case TargetTypeVo.Way:
                if (wayQty.compareTo(model.getQty()) < 0) {
                    throw new InventoryException(model.getItem().getId(), itemIdName + " 在途库存不足：" + model.getQty().subtract(wayQty));
                }
                break;
            case TargetTypeVo.Storage:
                if (storageQty.compareTo(model.getQty()) < 0) {
                    throw new InventoryException(model.getItem().getId(), itemIdName + " 暂存库存不足：" + model.getQty().subtract(storageQty));
                }
                break;
            case TargetTypeVo.RejectLock:
                if (rejectLockQty.compareTo(model.getQty()) < 0) {
                    throw new InventoryException(model.getItem().getId(), itemIdName + " 次品锁定库存不足：" + model.getQty().subtract(rejectLockQty));
                }
                break;
            case TargetTypeVo.RejectWay:
                if (rejectWayQty.compareTo(model.getQty()) < 0) {
                    throw new InventoryException(model.getItem().getId(), itemIdName + " 次品在途库存不足：" + model.getQty().subtract(rejectWayQty));
                }
                break;
            case TargetTypeVo.Inspected:
                if (inspectedQty.compareTo(model.getQty()) < 0) {
                    throw new InventoryException(model.getItem().getId(), itemIdName + " 待检库存不足：" + model.getQty().subtract(inspectedQty));
                }
                break;
            case TargetTypeVo.Picking:
                if (pickingQty.compareTo(model.getQty()) < 0) {
                    throw new InventoryException(model.getItem().getId(), itemIdName + " 拣货库存不足：" + model.getQty().subtract(pickingQty));
                }
                break;
            default:
                throw new Exception("出库源类型不明确");
        }
    }

    private void verificationOutboundInventory(InventoryOutboundVo model, List<Inventory> inventoryList) throws Exception {
        //校验库存是否有那么多
        BigDecimal stockQty = inventoryList.stream().filter(c -> c.getStockQty() != null).map(Inventory::getStockQty).reduce(BigDecimal.ZERO, BigDecimal::add);
        BigDecimal lockQty = inventoryList.stream().filter(c -> c.getLockQty() != null).map(Inventory::getLockQty).reduce(BigDecimal.ZERO, BigDecimal::add);
        BigDecimal detDefectQty = inventoryList.stream().filter(c -> c.getDefectQty() != null).map(Inventory::getDefectQty).reduce(BigDecimal.ZERO, BigDecimal::add);
        BigDecimal displayQty = inventoryList.stream().filter(c -> c.getDisplayQty() != null).map(Inventory::getDisplayQty).reduce(BigDecimal.ZERO, BigDecimal::add);
        BigDecimal wayQty = inventoryList.stream().filter(c -> c.getWayQty() != null).map(Inventory::getWayQty).reduce(BigDecimal.ZERO, BigDecimal::add);
        BigDecimal storageQty = inventoryList.stream().filter(c -> c.getStorageQty() != null).map(Inventory::getStorageQty).reduce(BigDecimal.ZERO, BigDecimal::add);
        BigDecimal rejectLockQty = inventoryList.stream().filter(c -> c.getRejectLockQty() != null).map(Inventory::getRejectLockQty).reduce(BigDecimal.ZERO, BigDecimal::add);
        BigDecimal rejectWayQty = inventoryList.stream().filter(c -> c.getRejectWayQty() != null).map(Inventory::getRejectWayQty).reduce(BigDecimal.ZERO, BigDecimal::add);
        BigDecimal inspectedQty = inventoryList.stream().filter(c -> c.getInspectedQty() != null).map(Inventory::getInspectedQty).reduce(BigDecimal.ZERO, BigDecimal::add);
        BigDecimal pickingQty = inventoryList.stream().filter(c -> c.getPickingQty() != null).map(Inventory::getPickingQty).reduce(BigDecimal.ZERO, BigDecimal::add);
        //可用 = 可用 -对应的锁库 - 残次 - 陈列 不能大于当前的库存
        stockQty = stockQty.subtract(lockQty.add(detDefectQty).add(displayQty));
        //暂存 = 暂存 + 可用
        storageQty = NumberUtil.add(storageQty, stockQty);
        String itemIdName = "";
        if (StringUtils.isNotBlank(MaterialConfig.sql)) {
            try {
                String sql = String.format(MaterialConfig.sql, model.getItem().getId());
                itemIdName = inventoryMapper.selectMaterial(sql);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        switch (model.getFrom().getValue()) {
            case TargetTypeVo.Normal:

                if (stockQty.compareTo(model.getQty()) < 0) {
                    //throw new InventoryException(model.getItem().getId(),itemIdName+" 出库数量大于库存数量-锁库数量-残次数量 库存数："+stockQty.subtract(lockQty.add(detDefectQty)));
                    throw new InventoryException(model.getItem().getId(), itemIdName + "  库存不足：" + model.getQty().subtract(stockQty));
                }
                break;
            case TargetTypeVo.Lock:
                if (lockQty.compareTo(model.getQty()) < 0) {
                    throw new InventoryException(model.getItem().getId(), itemIdName + " 锁库库存不足：" + model.getQty().subtract(lockQty));
                }
                break;
            case TargetTypeVo.Display:
                if (displayQty.compareTo(model.getQty()) < 0) {
                    throw new InventoryException(model.getItem().getId(), itemIdName + " 展品库存不足：" + model.getQty().subtract(displayQty));
                }
                break;
            case TargetTypeVo.Defect:
                if (detDefectQty.compareTo(model.getQty()) < 0) {
                    throw new InventoryException(model.getItem().getId(), itemIdName + " 残次库存不足：" + model.getQty().subtract(detDefectQty));
                }
                break;
            case TargetTypeVo.Way:
                if (wayQty.compareTo(model.getQty()) < 0) {
                    throw new InventoryException(model.getItem().getId(), itemIdName + " 在途库存不足：" + model.getQty().subtract(wayQty));
                }
                break;
            case TargetTypeVo.Storage:
                if (storageQty.compareTo(model.getQty()) < 0) {
                    throw new InventoryException(model.getItem().getId(), itemIdName + " 暂存库存不足：" + model.getQty().subtract(storageQty));
                }
                break;
            case TargetTypeVo.RejectLock:
                if (rejectLockQty.compareTo(model.getQty()) < 0) {
                    throw new InventoryException(model.getItem().getId(), itemIdName + " 次品锁定库存不足：" + model.getQty().subtract(rejectLockQty));
                }
                break;
            case TargetTypeVo.RejectWay:
                if (rejectWayQty.compareTo(model.getQty()) < 0) {
                    throw new InventoryException(model.getItem().getId(), itemIdName + " 次品在途库存不足：" + model.getQty().subtract(rejectWayQty));
                }
                break;
            case TargetTypeVo.Inspected:
                if (inspectedQty.compareTo(model.getQty()) < 0) {
                    throw new InventoryException(model.getItem().getId(), itemIdName + " 待检库存不足：" + model.getQty().subtract(inspectedQty));
                }
                break;
            case TargetTypeVo.Picking:
                if (pickingQty.compareTo(model.getQty()) < 0) {
                    throw new InventoryException(model.getItem().getId(), itemIdName + " 拣货库存不足：" + model.getQty().subtract(pickingQty));
                }
                break;
            default:
                throw new Exception("出库源类型不明确");
        }
    }

    private String queryWrapperInventoryOutboundDescOrAsc(InventoryOutboundVo model) throws Exception {
        String descOrAsc = "";
        switch (model.getModel().getValue()) {
            case PatternVo.FIFO:
                descOrAsc = "asc";
                break;
            case PatternVo.LIFO:
                descOrAsc = "desc";
                break;
            case PatternVo.ExpiryEarlier:
                //近有效期先出"不新鲜" ？？
                descOrAsc = "asc";
                break;
            case PatternVo.ExpiryLater:
                descOrAsc = "desc";
                break;
            default:
                throw new Exception("对应模式不符合");
        }
        return descOrAsc;
    }


    private InventoryListReturnVo outboundUpdate(InventoryOutboundVo model, List<Inventory> inventoryList, List<BinIdsVo> binIdsVos) throws Exception {
        InventoryListReturnVo inventoryListReturnVo = new InventoryListReturnVo();
        // 要处理的量
        BigDecimal qtySum = model.getQty();
        List<Long> updateIds = new ArrayList<>();
        List<Long> delIds = new ArrayList<>();
        List<Long> variationIds = new ArrayList<>();
        for (Inventory inventory : inventoryList) {
            if (qtySum.compareTo(BigDecimal.ZERO) == 0) {
                //库存都处理完
                break;
            }
            updateIds.add(inventory.getId());
            InventoryVariation inventoryVariation = new InventoryVariation();
            LambdaUpdateChainWrapper<Inventory> inventoryUpdateChainWrapper = new LambdaUpdateChainWrapper<>(inventoryMapper);

            inventoryUpdateChainWrapper.eq(Inventory::getId, inventory.getId());
            inventoryUpdateChainWrapper.eq(Inventory::getVersion, inventory.getVersion());
            inventoryUpdateChainWrapper.set(Inventory::getVersion, inventory.getVersion() + 1);

            Inventory updateInventory = new Inventory();
            updateInventory.setId(inventory.getId());
            BeanUtils.copyProperties(model, inventoryVariation);
            inventoryVariation.setChangeType("Out");
            inventoryVariation.setFromType(model.getFrom().getValue());
            inventoryVariation.setItemId(model.getItem().getId());
            inventoryVariation.setOperateTime(new Date());
            inventoryVariation.setStockQty(inventory.getStockQty());
            inventoryVariation.setLockQty(inventory.getLockQty());
            inventoryVariation.setDisplayQty(inventory.getDisplayQty());
            inventoryVariation.setDefectQty(inventory.getDefectQty());
            inventoryVariation.setWayQty(inventory.getWayQty());
            inventoryVariation.setStorageQty(inventory.getStorageQty());
            inventoryVariation.setRejectLockQty(inventory.getRejectLockQty());
            inventoryVariation.setRejectWayQty(inventory.getRejectWayQty());
            inventoryVariation.setInspectedQty(inventory.getInspectedQty());

            BigDecimal stockQty = orZero(inventory.getStockQty());
            BigDecimal lockQty = orZero(inventory.getLockQty());
            BigDecimal detDefectQty = orZero(inventory.getDefectQty());
            BigDecimal wayQty = orZero(inventory.getWayQty());
            BigDecimal displayQty = orZero(inventory.getDisplayQty());
            BigDecimal normalQty = stockQty.subtract(lockQty).subtract(detDefectQty).subtract(displayQty);
            BigDecimal storageQty = orZero(inventory.getStorageQty());
            BigDecimal rejectLockQty = orZero(inventory.getRejectLockQty());
            BigDecimal rejectWayQty = orZero(inventory.getRejectWayQty());
            BigDecimal inspectedQty = orZero(inventory.getInspectedQty());
            BigDecimal pickingQty = orZero(inventory.getPickingQty());

            switch (model.getFrom().getValue()) {
                case TargetTypeVo.Normal:
                    if (!getIsOpenNegativeInventory(model.getStockId())) {
                        updateInventory.setStockQty(stockQty.subtract(qtySum));
                        inventoryVariation.setStockQty(updateInventory.getStockQty());
                        inventoryVariation.setChangeStockQty(qtySum.negate());
                        qtySum = BigDecimal.ZERO;
                    } else if (normalQty.compareTo(qtySum) >= 0) {
                        updateInventory.setStockQty(stockQty.subtract(qtySum));
                        inventoryVariation.setStockQty(updateInventory.getStockQty());
                        inventoryVariation.setChangeStockQty(qtySum.negate());
                        qtySum = BigDecimal.ZERO;
                    } else {
                        updateInventory.setStockQty(stockQty.subtract(normalQty));
                        inventoryVariation.setStockQty(updateInventory.getStockQty());
                        inventoryVariation.setChangeStockQty(updateInventory.getStockQty().negate());
                        qtySum = qtySum.subtract(normalQty);
                    }
                    // updateInventory.setStockQty(inventoryVariation.getStockQty());
                    inventoryUpdateChainWrapper.set(Inventory::getStockQty, updateInventory.getStockQty());
                    if (!inventoryUpdateChainWrapper.update()) {
                        throw new Exception("数据版本错误，更新失败");
                    }
                    //this.updateById(updateInventory);
                    //校验 所有数量是否等于0 都是的的删除
//                    if (isZero(updateInventory.getStockQty(), lockQty, detDefectQty, wayQty, displayQty)) {
//                        this.removeById(updateInventory.getId());
//                        delIds.add(updateInventory.getId());
//                    }
                    break;
                case TargetTypeVo.Lock:
//                    if(lockQty.compareTo(model.getQty())==-1){
//                        throw new Exception("出库数量大于锁库数量");
//                    }
                    if (!getIsOpenNegativeInventory(model.getStockId())) {
                        updateInventory.setStockQty(stockQty.subtract(qtySum));
                        updateInventory.setLockQty(lockQty.subtract(qtySum));
                        inventoryVariation.setStockQty(updateInventory.getStockQty());
                        inventoryVariation.setLockQty(updateInventory.getLockQty());
                        inventoryVariation.setChangeLockQty(qtySum.negate());
                        inventoryVariation.setChangeStockQty(qtySum.negate());
                        qtySum = BigDecimal.ZERO;
                    } else if (lockQty.compareTo(qtySum) >= 0) {
                        updateInventory.setStockQty(stockQty.subtract(qtySum));
                        updateInventory.setLockQty(lockQty.subtract(qtySum));
                        inventoryVariation.setStockQty(updateInventory.getStockQty());
                        inventoryVariation.setLockQty(updateInventory.getLockQty());
                        inventoryVariation.setChangeLockQty(qtySum.negate());
                        inventoryVariation.setChangeStockQty(qtySum.negate());
                        qtySum = BigDecimal.ZERO;
                    } else {
                        updateInventory.setStockQty(stockQty.subtract(lockQty));
                        updateInventory.setLockQty(BigDecimal.ZERO);
                        inventoryVariation.setLockQty(updateInventory.getLockQty());
                        inventoryVariation.setStockQty(updateInventory.getStockQty());
                        inventoryVariation.setChangeLockQty(lockQty.negate());
                        inventoryVariation.setChangeStockQty(lockQty.negate());
                        qtySum = qtySum.subtract(lockQty);
                    }
                    //  inventoryVariation.setLockQty(model.getQty());
                    // updateInventory.setStockQty(stockQty.subtract(model.getQty()));
                    //  updateInventory.setLockQty(lockQty.subtract(model.getQty()));
                    inventoryUpdateChainWrapper.set(Inventory::getStockQty, updateInventory.getStockQty());
                    inventoryUpdateChainWrapper.set(Inventory::getLockQty, updateInventory.getLockQty());
                    if (!inventoryUpdateChainWrapper.update()) {
                        throw new Exception("数据版本错误，更新失败");
                    }
                    //this.updateById(updateInventory);
//                    if (isZero(updateInventory.getStockQty(), updateInventory.getLockQty(), detDefectQty, wayQty, displayQty)) {
//                        this.removeById(updateInventory.getId());
//                        delIds.add(updateInventory.getId());
//                    }
                    break;
                case TargetTypeVo.Display:
//                    if(displayQty.compareTo(model.getQty())==-1){
//                        throw new Exception("出库数量大于展品数量");
//                    }
                    if (!getIsOpenNegativeInventory(model.getStockId())) {
                        updateInventory.setStockQty(stockQty.subtract(qtySum));
                        updateInventory.setDisplayQty(displayQty.subtract(qtySum));
                        inventoryVariation.setDisplayQty(updateInventory.getDisplayQty());
                        inventoryVariation.setStockQty(updateInventory.getStockQty());
                        inventoryVariation.setChangeDisplayQty(qtySum.negate());
                        inventoryVariation.setChangeStockQty(qtySum.negate());
                        qtySum = BigDecimal.ZERO;
                    } else if (displayQty.compareTo(qtySum) >= 0) {
                        updateInventory.setStockQty(stockQty.subtract(qtySum));
                        updateInventory.setDisplayQty(displayQty.subtract(qtySum));
                        inventoryVariation.setDisplayQty(updateInventory.getDisplayQty());
                        inventoryVariation.setStockQty(updateInventory.getStockQty());
                        inventoryVariation.setChangeDisplayQty(qtySum.negate());
                        inventoryVariation.setChangeStockQty(qtySum.negate());
                        qtySum = BigDecimal.ZERO;
                    } else {
                        updateInventory.setLockQty(BigDecimal.ZERO);
                        updateInventory.setStockQty(stockQty.subtract(displayQty));
                        inventoryVariation.setLockQty(updateInventory.getLockQty());
                        inventoryVariation.setStockQty(updateInventory.getStockQty());
                        inventoryVariation.setChangeLockQty(displayQty.negate());
                        inventoryVariation.setChangeStockQty(displayQty.negate());
                        qtySum = qtySum.subtract(displayQty);
                    }

                    //  inventoryVariation.setDisplayQty(model.getQty());
                    //  updateInventory.setDisplayQty(displayQty.subtract(model.getQty()));
                    inventoryUpdateChainWrapper.set(Inventory::getDisplayQty, updateInventory.getDisplayQty());
                    if (!inventoryUpdateChainWrapper.update()) {
                        throw new Exception("数据版本错误，更新失败");
                    }
                    //this.updateById(updateInventory);
//                    if (isZero(stockQty, lockQty, detDefectQty, wayQty, updateInventory.getDisplayQty())) {
//                        this.removeById(updateInventory.getId());
//                        delIds.add(updateInventory.getId());
//                    }
                    break;
                case TargetTypeVo.Defect:
//                    if(detDefectQty.compareTo(model.getQty())==-1){
//                        throw new Exception("出库数量大于残次数量");
//                    }
                    if (!getIsOpenNegativeInventory(model.getStockId())) {
                        updateInventory.setStockQty(stockQty.subtract(qtySum));
                        updateInventory.setDefectQty(detDefectQty.subtract(qtySum));
                        inventoryVariation.setStockQty(updateInventory.getStockQty());
                        inventoryVariation.setDefectQty(updateInventory.getDefectQty());
                        inventoryVariation.setChangeStockQty(qtySum.negate());
                        inventoryVariation.setChangeDefectQty(qtySum.negate());
                        qtySum = BigDecimal.ZERO;
                    } else if (detDefectQty.compareTo(qtySum) >= 0) {
                        updateInventory.setStockQty(stockQty.subtract(qtySum));
                        updateInventory.setDefectQty(detDefectQty.subtract(qtySum));
                        inventoryVariation.setStockQty(updateInventory.getStockQty());
                        inventoryVariation.setDefectQty(updateInventory.getDefectQty());
                        inventoryVariation.setChangeStockQty(qtySum.negate());
                        inventoryVariation.setChangeDefectQty(qtySum.negate());
                        qtySum = BigDecimal.ZERO;
                    } else {
                        updateInventory.setStockQty(stockQty.subtract(detDefectQty));
                        updateInventory.setDefectQty(BigDecimal.ZERO);
                        inventoryVariation.setStockQty(updateInventory.getStockQty());
                        inventoryVariation.setDefectQty(updateInventory.getDefectQty());
                        inventoryVariation.setChangeStockQty(detDefectQty.negate());
                        inventoryVariation.setDefectQty(detDefectQty.negate());
                        qtySum = qtySum.subtract(detDefectQty);
                    }
//                    inventoryVariation.setDefectQty(model.getQty());
//                    updateInventory.setStockQty(stockQty.subtract(model.getQty()));
//                    updateInventory.setDefectQty(lockQty.subtract(model.getQty()));
                    inventoryUpdateChainWrapper.set(Inventory::getStockQty, updateInventory.getStockQty());
                    inventoryUpdateChainWrapper.set(Inventory::getDefectQty, updateInventory.getDefectQty());
                    if (!inventoryUpdateChainWrapper.update()) {
                        throw new Exception("数据版本错误，更新失败");
                    }
                    //this.updateById(updateInventory);
//                    if (isZero(updateInventory.getStockQty(), lockQty, updateInventory.getDefectQty(), wayQty, displayQty)) {
//                        this.removeById(updateInventory.getId());
//                        delIds.add(updateInventory.getId());
//                    }
                    break;
                case TargetTypeVo.Way:
//                    if (wayQty.compareTo(model.getQty()) == -1) {
//                        throw new Exception("出库数量大于在途数量");
//                    }
                    if (!getIsOpenNegativeInventory(model.getStockId())) {
                        updateInventory.setWayQty(wayQty.subtract(qtySum));
                        inventoryVariation.setWayQty(updateInventory.getWayQty());
                        inventoryVariation.setChangeWayQty(qtySum.negate());
                        qtySum = BigDecimal.ZERO;
                    } else if (wayQty.compareTo(qtySum) >= 0) {
                        updateInventory.setWayQty(wayQty.subtract(qtySum));
                        inventoryVariation.setWayQty(updateInventory.getWayQty());
                        inventoryVariation.setChangeWayQty(qtySum.negate());
                        qtySum = BigDecimal.ZERO;
                    } else {
                        updateInventory.setWayQty(BigDecimal.ZERO);
                        inventoryVariation.setWayQty(updateInventory.getWayQty());
                        inventoryVariation.setChangeWayQty(wayQty.negate());
                        qtySum = qtySum.subtract(wayQty);
                    }
                    // inventoryVariation.setWayQty(model.getQty());
                    //  updateInventory.setWayQty(wayQty.subtract(model.getQty()));
                    inventoryUpdateChainWrapper.set(Inventory::getWayQty, updateInventory.getWayQty());
                    if (!inventoryUpdateChainWrapper.update()) {
                        throw new Exception("数据版本错误，更新失败");
                    }
                    //this.updateById(updateInventory);
//                    if (isZero(stockQty, lockQty, detDefectQty, updateInventory.getWayQty(), displayQty)) {
//                        this.removeById(updateInventory.getId());
//                        delIds.add(updateInventory.getId());
//                    }
                    break;
//                case TargetTypeVo.Storage:
//                    if (!getIsOpenNegativeInventory(model.getStockId())) {
//                        updateInventory.setStorageQty(storageQty.subtract(qtySum));
//                        inventoryVariation.setStorageQty(updateInventory.getStorageQty());
//                        inventoryVariation.setChangeStorageQty(qtySum.negate());
//                        qtySum = BigDecimal.ZERO;
//                    } else if (storageQty.compareTo(qtySum) >= 0) {
//                        updateInventory.setStorageQty(storageQty.subtract(qtySum));
//                        inventoryVariation.setStorageQty(updateInventory.getStorageQty());
//                        inventoryVariation.setChangeStorageQty(qtySum.negate());
//                        qtySum = BigDecimal.ZERO;
//                    } else {
//                        updateInventory.setStorageQty(BigDecimal.ZERO);
//                        inventoryVariation.setStorageQty(updateInventory.getStorageQty());
//                        inventoryVariation.setChangeStorageQty(storageQty.negate());
//                        qtySum = qtySum.subtract(storageQty);
//                    }


                case TargetTypeVo.Storage:
                    if (!getIsOpenNegativeInventory(model.getStockId()) || storageQty.compareTo(qtySum) >= 0) { //开启负库存 || 暂存数量够
                        updateInventory.setStorageQty(storageQty.subtract(qtySum));
                        inventoryVariation.setStorageQty(updateInventory.getStorageQty());
                        inventoryVariation.setChangeStorageQty(qtySum.negate());
                        qtySum = BigDecimal.ZERO;
                    } else if (NumberUtil.isGreater(NumberUtil.add(normalQty, storageQty), qtySum)) {   //暂存 + 可用够
                        updateInventory.setStorageQty(BigDecimal.ZERO);
                        updateInventory.setStockQty(stockQty.subtract(qtySum.subtract(storageQty))); //剩余可用(锁定 + 陈列 + 残次) = 总可用 - 可用
                        inventoryVariation.setStorageQty(BigDecimal.ZERO);
                        inventoryVariation.setStockQty(stockQty.subtract(qtySum.subtract(storageQty)));
                        inventoryVariation.setChangeStorageQty(storageQty.negate());
                        inventoryVariation.setChangeStockQty(qtySum.subtract(storageQty).negate());
                        qtySum = BigDecimal.ZERO;
                    } else {   //暂存 + 可用不够:扣完
                        updateInventory.setStorageQty(BigDecimal.ZERO);
                        updateInventory.setStockQty(NumberUtil.sub(stockQty, normalQty)); //剩余可用(锁定 + 陈列 + 残次) = 总可用 - 可用
                        inventoryVariation.setStorageQty(BigDecimal.ZERO);
                        inventoryVariation.setStockQty(NumberUtil.sub(stockQty, normalQty));
                        inventoryVariation.setChangeStorageQty(storageQty.negate());
                        inventoryVariation.setChangeStockQty(normalQty.negate());
                        qtySum = qtySum.subtract(NumberUtil.add(normalQty, storageQty));
                    }

                    inventoryUpdateChainWrapper.set(Inventory::getStorageQty, updateInventory.getStorageQty());
                    if (!inventoryUpdateChainWrapper.update()) {
                        throw new Exception("数据版本错误，更新失败");
                    }

                    break;
                case TargetTypeVo.RejectLock:
                    if (!getIsOpenNegativeInventory(model.getStockId())) {
                        updateInventory.setRejectLockQty(rejectLockQty.subtract(qtySum));
                        inventoryVariation.setRejectLockQty(updateInventory.getRejectLockQty());
                        inventoryVariation.setChangeRejectLockQty(qtySum.negate());
                        qtySum = BigDecimal.ZERO;
                    } else if (rejectLockQty.compareTo(qtySum) >= 0) {
                        updateInventory.setRejectLockQty(rejectLockQty.subtract(qtySum));
                        inventoryVariation.setRejectLockQty(updateInventory.getRejectLockQty());
                        inventoryVariation.setChangeRejectLockQty(qtySum.negate());
                        qtySum = BigDecimal.ZERO;
                    } else {
                        updateInventory.setRejectLockQty(BigDecimal.ZERO);
                        inventoryVariation.setRejectLockQty(updateInventory.getRejectLockQty());
                        inventoryVariation.setChangeRejectLockQty(rejectLockQty.negate());
                        qtySum = qtySum.subtract(rejectLockQty);
                    }
                    inventoryUpdateChainWrapper.set(Inventory::getRejectLockQty, updateInventory.getRejectLockQty());
                    if (!inventoryUpdateChainWrapper.update()) {
                        throw new Exception("数据版本错误，更新失败");
                    }

                    break;
                case TargetTypeVo.RejectWay:
                    if (!getIsOpenNegativeInventory(model.getStockId())) {
                        updateInventory.setRejectWayQty(rejectWayQty.subtract(qtySum));
                        inventoryVariation.setRejectWayQty(updateInventory.getRejectWayQty());
                        inventoryVariation.setChangeRejectWayQty(qtySum.negate());
                        qtySum = BigDecimal.ZERO;
                    } else if (rejectWayQty.compareTo(qtySum) >= 0) {
                        updateInventory.setRejectWayQty(rejectWayQty.subtract(qtySum));
                        inventoryVariation.setRejectWayQty(updateInventory.getRejectWayQty());
                        inventoryVariation.setChangeRejectWayQty(qtySum.negate());
                        qtySum = BigDecimal.ZERO;
                    } else {
                        updateInventory.setRejectWayQty(BigDecimal.ZERO);
                        inventoryVariation.setRejectWayQty(updateInventory.getRejectWayQty());
                        inventoryVariation.setChangeRejectWayQty(rejectWayQty.negate());
                        qtySum = qtySum.subtract(rejectWayQty);
                    }
                    inventoryUpdateChainWrapper.set(Inventory::getRejectWayQty, updateInventory.getRejectWayQty());
                    if (!inventoryUpdateChainWrapper.update()) {
                        throw new Exception("数据版本错误，更新失败");
                    }

                    break;
                case TargetTypeVo.Inspected:
                    if (!getIsOpenNegativeInventory(model.getStockId())) {
                        updateInventory.setInspectedQty(inspectedQty.subtract(qtySum));
                        inventoryVariation.setInspectedQty(updateInventory.getInspectedQty());
                        inventoryVariation.setChangeInspectedQty(qtySum.negate());
                        qtySum = BigDecimal.ZERO;
                    } else if (inspectedQty.compareTo(qtySum) >= 0) {
                        updateInventory.setInspectedQty(inspectedQty.subtract(qtySum));
                        inventoryVariation.setInspectedQty(updateInventory.getInspectedQty());
                        inventoryVariation.setChangeInspectedQty(qtySum.negate());
                        qtySum = BigDecimal.ZERO;
                    } else {
                        updateInventory.setInspectedQty(BigDecimal.ZERO);
                        inventoryVariation.setInspectedQty(updateInventory.getInspectedQty());
                        inventoryVariation.setChangeInspectedQty(inspectedQty.negate());
                        qtySum = qtySum.subtract(inspectedQty);
                    }
                    inventoryUpdateChainWrapper.set(Inventory::getInspectedQty, updateInventory.getInspectedQty());
                    if (!inventoryUpdateChainWrapper.update()) {
                        throw new Exception("数据版本错误，更新失败");
                    }

                    break;
                case TargetTypeVo.Picking:
                    if (!getIsOpenNegativeInventory(model.getStockId())) {
                        updateInventory.setPickingQty(pickingQty.subtract(qtySum));
                        inventoryVariation.setPickingQty(updateInventory.getPickingQty());
                        inventoryVariation.setChangePickingQty(qtySum.negate());
                        qtySum = BigDecimal.ZERO;
                    } else if (pickingQty.compareTo(qtySum) >= 0) {
                        updateInventory.setPickingQty(pickingQty.subtract(qtySum));
                        inventoryVariation.setPickingQty(updateInventory.getPickingQty());
                        inventoryVariation.setChangePickingQty(qtySum.negate());
                        qtySum = BigDecimal.ZERO;
                    } else {
                        updateInventory.setPickingQty(BigDecimal.ZERO);
                        inventoryVariation.setPickingQty(updateInventory.getPickingQty());
                        inventoryVariation.setChangePickingQty(pickingQty.negate());
                        qtySum = qtySum.subtract(pickingQty);
                    }
                    inventoryUpdateChainWrapper.set(Inventory::getPickingQty, updateInventory.getPickingQty());
                    if (!inventoryUpdateChainWrapper.update()) {
                        throw new Exception("数据版本错误，更新失败");
                    }

                    break;

                default:
                    throw new Exception("出库源类型不明确");
            }
            inventoryVariationMapper.insert(inventoryVariation);
            if (binIdsVos.size() != 0) {
                List<InventoryPlacement> inventoryPlacementList = new ArrayList<>();
                for (BinIdsVo binIdsVo : binIdsVos) {
                    if (ObjectUtils.isEmpty(binIdsVo.getBinId())) {
                        //如果使用的是调拨的海岸之前的  不然按照新的处理
                        if ("调拨出库".equals(model.getOperate())) {
                            if (model.getFrom().getValue().equals(TargetTypeVo.Defect)) {
                                binIdsVo.setBinId(getSearchByWarehouseBin(model.getStockId(), model.getShopId(), model.getFnSku(), model.getItem().getId(), 2));
                                inventoryPlacementList = inventoryPlacementMapper.selectOutboundByWhereList(model, binIdsVo.getBinId());

                            } else {
                                binIdsVo.setBinId(getSearchByWarehouseBin(model.getStockId(), model.getShopId(), model.getFnSku(), model.getItem().getId(), 1));
                                inventoryPlacementList = inventoryPlacementMapper.selectOutboundByWhereList(model, binIdsVo.getBinId());
                            }
                        } else {
                            if (model.getFrom().getValue().equals(TargetTypeVo.Defect)) {
                                binIdsVo.setBinId(getSearchByWarehouseBin(model.getStockId(), model.getShopId(), model.getFnSku(), model.getItem().getId(), 2));
                            } else {
                                //查询 可用暂存 在查询可用仓位进行出处理
                                try {
                                    binIdsVo.setBinId(getSearchByWarehouseBin(model.getStockId(), model.getShopId(), model.getFnSku(), model.getItem().getId(), 1));
                                    List<InventoryPlacement> inventoryPlacementList1 = inventoryPlacementMapper.selectOutboundByWhereList(model, binIdsVo.getBinId());
                                    if (CollectionUtils.isNotEmpty(inventoryPlacementList1)) {
                                        inventoryPlacementList.addAll(inventoryPlacementList1);
                                    }
                                } catch (Exception e) {
                                    //没查到对应仓位 不处理
                                }
                                try {
                                    Long BinId = getSearchByWarehouseBin(model.getStockId(), model.getShopId(), model.getFnSku(), model.getItem().getId(), 3);
                                    List<InventoryPlacement> inventoryPlacementList2 = inventoryPlacementMapper.selectOutboundByWhereList(model, BinId);
                                    if (CollectionUtils.isNotEmpty(inventoryPlacementList2)) {
                                        inventoryPlacementList.addAll(inventoryPlacementList2);
                                    }
                                } catch (Exception e) {
                                    //没查到对应仓位 不处理
                                }
                            }
                        }

                    } else {
                        inventoryPlacementList = inventoryPlacementMapper.selectOutboundByWhereList(model, binIdsVo.getBinId());
                    }


                    if (CollectionUtils.isEmpty(inventoryPlacementList)) {
                        if (getIsOpenNegativeInventory(model.getStockId())) {
                            throw new Exception(getItemIdName(model.getItem().getId()) + "没有对应库位内码");
                        } else {
                            InventoryPlacement insertInventoryPlacement = new InventoryPlacement();
                            BeanUtils.copyProperties(model, insertInventoryPlacement);
                            insertInventoryPlacement.setBinId(binIdsVo.getBinId());
                            // insertInventoryPlacement.setStockQty(new BigDecimal(binIdsVo.getQty()));
                            insertInventoryPlacement.setAuxId(model.getItem().getId());
                            insertInventoryPlacement.setItemId(model.getItem().getId());
                            if (StringUtils.isBlank(model.getBatchNo())) {
                                insertInventoryPlacement.setBatchNo(null);
                            }
                            inventoryPlacementMapper.insert(insertInventoryPlacement);
                            inventoryPlacementList = inventoryPlacementMapper.selectOutboundByWhereList(model, binIdsVo.getBinId());
                        }
                    }
                    BigDecimal stockQtySum = inventoryPlacementList.stream().filter(c -> c.getStockQty() != null).map(InventoryPlacement::getStockQty).reduce(BigDecimal.ZERO, BigDecimal::add);
                    BigDecimal LockQtySum = inventoryPlacementList.stream().filter(c -> c.getLockQty() != null).map(InventoryPlacement::getLockQty).reduce(BigDecimal.ZERO, BigDecimal::add);
                    BigDecimal WayQtySum = inventoryPlacementList.stream().filter(c -> c.getWayQty() != null).map(InventoryPlacement::getWayQty).reduce(BigDecimal.ZERO, BigDecimal::add);

                    if (getIsOpenNegativeInventory(model.getStockId())) {
                        switch (model.getFromBinIdsType().getValue()) {
                            case TargetTypeVo.Normal:
                                if (stockQtySum.compareTo(new BigDecimal(binIdsVo.getQty())) == -1) {
                                    throw new Exception("库存货位放置表正常库存不足");
                                }
                                //inventoryPlacementVariation.setChangeStockQty(new BigDecimal(binIdsVo.getQty()).negate() );
                                // inventoryPlacementVariation.setStockQty(stockQtySum.subtract(new BigDecimal(binIdsVo.getQty())));
                                break;
                            case TargetTypeVo.Lock:
                                if (LockQtySum.compareTo(new BigDecimal(binIdsVo.getQty())) == -1) {
                                    throw new Exception("库存货位放置表锁定库存不足");
                                }
                                // inventoryPlacementVariation.setChangeLockQty(new BigDecimal(binIdsVo.getQty()).negate() );
                                // inventoryPlacementVariation.setLockQty(LockQtySum.subtract(new BigDecimal(binIdsVo.getQty())));
                                break;
                            case TargetTypeVo.Way:
                                if (WayQtySum.compareTo(new BigDecimal(binIdsVo.getQty())) == -1) {
                                    throw new Exception("库存货位放置表在途库存不足");
                                }
                                // inventoryPlacementVariation.setChangeWayQty(new BigDecimal(binIdsVo.getQty()).negate() );
                                //  inventoryPlacementVariation.setWayQty(WayQtySum.subtract(new BigDecimal(binIdsVo.getQty())));
                                break;
                            default:
                                throw new Exception("出库位类型不明确");
                        }
                    } else {
                        switch (model.getFromBinIdsType().getValue()) {
                            case TargetTypeVo.Normal:
                                // inventoryPlacementVariation.setChangeStockQty(new BigDecimal(binIdsVo.getQty()).negate() );
                                // inventoryPlacementVariation.setStockQty(stockQtySum.subtract(new BigDecimal(binIdsVo.getQty())));
                                break;
                            case TargetTypeVo.Lock:
                                // inventoryPlacementVariation.setChangeLockQty(new BigDecimal(binIdsVo.getQty()).negate() );
                                //  inventoryPlacementVariation.setLockQty(LockQtySum.subtract(new BigDecimal(binIdsVo.getQty())));
                                break;
                            case TargetTypeVo.Way:
                                // inventoryPlacementVariation.setChangeWayQty(new BigDecimal(binIdsVo.getQty()).negate() );
                                // inventoryPlacementVariation.setWayQty(WayQtySum.subtract(new BigDecimal(binIdsVo.getQty())));
                                break;
                            default:
                                throw new Exception("出库位类型不明确");
                        }
                    }
                    BigDecimal outQtySum = new BigDecimal(binIdsVo.getQty());
                    for (InventoryPlacement inventoryPlacement : inventoryPlacementList) {
                        if (outQtySum.compareTo(BigDecimal.ZERO) == 0) {
                            break;
                        }
                        InventoryPlacementVariation inventoryPlacementVariation = new InventoryPlacementVariation();
                        BeanUtils.copyProperties(model, inventoryPlacementVariation);
                        inventoryPlacementVariation.setChangeType("Out");
                        inventoryPlacementVariation.setFromType(model.getFromBinIdsType().getValue());
                        inventoryPlacementVariation.setItemId(model.getItem().getId());
                        inventoryPlacementVariation.setOperateTime(new Date());
                        inventoryPlacementVariation.setBinId(binIdsVo.getBinId());
                        inventoryPlacementVariation.setBinId(inventoryPlacement.getBinId());
                        inventoryPlacementVariation.setStockQty(inventoryPlacement.getStockQty());
                        inventoryPlacementVariation.setLockQty(inventoryPlacement.getLockQty());
                        inventoryPlacementVariation.setWayQty(inventoryPlacement.getWayQty());

                        LambdaUpdateChainWrapper<InventoryPlacement> inventoryPlacementUpdateChainWrapper = new LambdaUpdateChainWrapper<>(inventoryPlacementMapper);
                        switch (model.getFromBinIdsType().getValue()) {
                            case TargetTypeVo.Normal:
                                if (inventoryPlacement.getStockQty() == null) {
                                    inventoryPlacement.setStockQty(new BigDecimal(0));
                                }
                                if (outQtySum.compareTo(BigDecimal.ZERO) == 0) {
                                    break;
                                } else if (!getIsOpenNegativeInventory(model.getStockId())) {
                                    inventoryPlacementVariation.setChangeStockQty(new BigDecimal(binIdsVo.getQty()).negate());
                                    inventoryPlacementVariation.setStockQty(inventoryPlacement.getStockQty().subtract(new BigDecimal(binIdsVo.getQty())));
                                    inventoryPlacementUpdateChainWrapper.set(InventoryPlacement::getStockQty, inventoryPlacement.getStockQty().subtract(outQtySum));
                                    outQtySum = BigDecimal.ZERO;
                                } else if (outQtySum.compareTo(inventoryPlacement.getStockQty()) >= 0) {
                                    inventoryPlacementVariation.setChangeStockQty(inventoryPlacement.getStockQty().negate());
                                    inventoryPlacementVariation.setStockQty(BigDecimal.ZERO);
                                    outQtySum = outQtySum.subtract(inventoryPlacement.getStockQty());
                                    inventoryPlacementUpdateChainWrapper.set(InventoryPlacement::getStockQty, BigDecimal.ZERO);
                                    // inventoryPlacementUpdateChainWrapper.set(InventoryPlacement::getStockQty, inventoryPlacement.getStockQty().subtract(outQtySum));
                                    // outQtySum=BigDecimal.ZERO;
                                } else if (outQtySum.compareTo(inventoryPlacement.getStockQty()) == -1) {
                                    inventoryPlacementVariation.setChangeStockQty(outQtySum.negate());
                                    inventoryPlacementVariation.setStockQty(inventoryPlacement.getStockQty().subtract(outQtySum));
                                    inventoryPlacementUpdateChainWrapper.set(InventoryPlacement::getStockQty, inventoryPlacement.getStockQty().subtract(outQtySum));
                                    outQtySum = BigDecimal.ZERO;
                                }
                                inventoryPlacementUpdateChainWrapper.eq(InventoryPlacement::getId, inventoryPlacement.getId());
                                inventoryPlacementUpdateChainWrapper.eq(InventoryPlacement::getVersion, inventoryPlacement.getVersion());
                                inventoryPlacementUpdateChainWrapper.set(InventoryPlacement::getVersion, inventoryPlacement.getVersion() + 1);
                                if (!inventoryPlacementUpdateChainWrapper.update()) {
                                    throw new Exception("数据版本错误，更新失败");
                                }
                                break;
                            case TargetTypeVo.Lock:
                                if (inventoryPlacement.getLockQty() == null) {
                                    inventoryPlacement.setLockQty(new BigDecimal(0));
                                }
                                if (outQtySum.compareTo(BigDecimal.ZERO) == 0) {
                                    break;
                                } else if (!getIsOpenNegativeInventory(model.getStockId())) {
                                    inventoryPlacementVariation.setChangeLockQty(new BigDecimal(binIdsVo.getQty()).negate());
                                    inventoryPlacementVariation.setLockQty(inventoryPlacement.getLockQty().subtract(new BigDecimal(binIdsVo.getQty())));
                                    inventoryPlacementUpdateChainWrapper.set(InventoryPlacement::getLockQty, inventoryPlacement.getLockQty().subtract(outQtySum));
                                    outQtySum = BigDecimal.ZERO;
                                } else if (outQtySum.compareTo(inventoryPlacement.getLockQty()) >= 0) {
                                    inventoryPlacementVariation.setChangeLockQty(inventoryPlacement.getLockQty().negate());
                                    inventoryPlacementVariation.setLockQty(BigDecimal.ZERO);
                                    outQtySum = outQtySum.subtract(inventoryPlacement.getLockQty());
                                    inventoryPlacementUpdateChainWrapper.set(InventoryPlacement::getLockQty, BigDecimal.ZERO);
                                    //inventoryPlacementUpdateChainWrapper.set(InventoryPlacement::getLockQty, inventoryPlacement.getLockQty().subtract(outQtySum));
                                    // outQtySum=BigDecimal.ZERO;
                                } else if (outQtySum.compareTo(inventoryPlacement.getLockQty()) == -1) {
                                    inventoryPlacementVariation.setChangeLockQty(outQtySum.negate());
                                    inventoryPlacementVariation.setLockQty(inventoryPlacement.getLockQty().subtract(outQtySum));
                                    inventoryPlacementUpdateChainWrapper.set(InventoryPlacement::getLockQty, inventoryPlacement.getLockQty().subtract(outQtySum));
                                    outQtySum = BigDecimal.ZERO;
                                }
                                inventoryPlacementUpdateChainWrapper.eq(InventoryPlacement::getId, inventoryPlacement.getId());
                                inventoryPlacementUpdateChainWrapper.eq(InventoryPlacement::getVersion, inventoryPlacement.getVersion());
                                inventoryPlacementUpdateChainWrapper.set(InventoryPlacement::getVersion, inventoryPlacement.getVersion() + 1);
                                if (!inventoryPlacementUpdateChainWrapper.update()) {
                                    throw new Exception("数据版本错误，更新失败");
                                }
                                break;
                            case TargetTypeVo.Way:
                                if (inventoryPlacement.getWayQty() == null) {
                                    inventoryPlacement.setWayQty(new BigDecimal(0));
                                }
                                if (outQtySum.compareTo(BigDecimal.ZERO) == 0) {
                                    break;
                                } else if (!getIsOpenNegativeInventory(model.getStockId())) {
                                    inventoryPlacementVariation.setChangeWayQty(new BigDecimal(binIdsVo.getQty()).negate());
                                    inventoryPlacementVariation.setWayQty(inventoryPlacement.getWayQty().subtract(new BigDecimal(binIdsVo.getQty())));
                                    inventoryPlacementUpdateChainWrapper.set(InventoryPlacement::getWayQty, inventoryPlacement.getWayQty().subtract(outQtySum));
                                    outQtySum = BigDecimal.ZERO;
                                } else if (outQtySum.compareTo(inventoryPlacement.getWayQty()) >= 0) {
                                    inventoryPlacementVariation.setChangeWayQty(inventoryPlacement.getWayQty().negate());
                                    inventoryPlacementVariation.setWayQty(BigDecimal.ZERO);
                                    outQtySum = outQtySum.subtract(inventoryPlacement.getWayQty());
                                    inventoryPlacementUpdateChainWrapper.set(InventoryPlacement::getWayQty, BigDecimal.ZERO);
                                    //inventoryPlacementUpdateChainWrapper.set(InventoryPlacement::getLockQty, inventoryPlacement.getLockQty().subtract(outQtySum));
                                    // outQtySum=BigDecimal.ZERO;
                                } else if (outQtySum.compareTo(inventoryPlacement.getWayQty()) == -1) {
                                    inventoryPlacementVariation.setChangeWayQty(outQtySum.negate());
                                    inventoryPlacementVariation.setWayQty(inventoryPlacement.getWayQty().subtract(outQtySum));
                                    inventoryPlacementUpdateChainWrapper.set(InventoryPlacement::getWayQty, inventoryPlacement.getWayQty().subtract(outQtySum));
                                    outQtySum = BigDecimal.ZERO;
                                }
                                inventoryPlacementUpdateChainWrapper.eq(InventoryPlacement::getId, inventoryPlacement.getId());
                                inventoryPlacementUpdateChainWrapper.eq(InventoryPlacement::getVersion, inventoryPlacement.getVersion());
                                inventoryPlacementUpdateChainWrapper.set(InventoryPlacement::getVersion, inventoryPlacement.getVersion() + 1);
                                if (!inventoryPlacementUpdateChainWrapper.update()) {
                                    throw new Exception("数据版本错误，更新失败");
                                }
                                break;
                            default:
                                throw new Exception("出库位类型不明确");
                        }
                        inventoryPlacementVariationMapper.insert(inventoryPlacementVariation);
                    }
                }
            }
            variationIds.add(inventoryVariation.getId());

        }
        inventoryListReturnVo.setUpdateIds(updateIds);
        inventoryListReturnVo.setRemoveIds(delIds);
        inventoryListReturnVo.setVariationIds(variationIds);
        return inventoryListReturnVo;
    }

    /**
     * @param model 出库放置表 sql 处理
     * @param binId
     * @return
     * @throws Exception
     */
    private LambdaQueryWrapper<InventoryPlacement> queryWrapperInventoryPlacementOutboundSql(InventoryOutboundVo model, Integer binId) throws Exception {
        //过滤 条件 null也过滤
        LambdaQueryWrapper<InventoryPlacement> queryWrapper = new LambdaQueryWrapper<>();
        if (binId == null) {
            queryWrapper.isNull(InventoryPlacement::getBinId);
        } else {
            queryWrapper.eq(InventoryPlacement::getBinId, binId);
        }
        if (model.getStockId() == null) {
            queryWrapper.isNull(InventoryPlacement::getStockId);
        } else {
            queryWrapper.eq(InventoryPlacement::getStockId, model.getStockId());
        }
        if (model.getProjectId() == null) {
            queryWrapper.isNull(InventoryPlacement::getProjectId);
        } else {
            queryWrapper.eq(InventoryPlacement::getProjectId, model.getProjectId());
        }
        if (model.getItem().getId() == null) {
            queryWrapper.isNull(InventoryPlacement::getItemId);
        } else {
            queryWrapper.eq(InventoryPlacement::getItemId, model.getItem().getId());
        }
        if (StringUtils.isNotBlank(model.getBatchNo())) {
            queryWrapper.eq(InventoryPlacement::getBatchNo, model.getBatchNo());
        } else {
            queryWrapper.isNull(InventoryPlacement::getBatchNo);
        }
        switch (model.getModel().getValue()) {
            case PatternVo.FIFO:
                queryWrapper.orderByAsc(InventoryPlacement::getExpiryDate);
                break;
            case PatternVo.LIFO:
                queryWrapper.orderByDesc(InventoryPlacement::getExpiryDate);
                break;
            case PatternVo.ExpiryEarlier:
                //近有效期先出"不新鲜" ？？
                queryWrapper.orderByAsc(InventoryPlacement::getExpiryDate);
                break;
            case PatternVo.ExpiryLater:
                queryWrapper.orderByDesc(InventoryPlacement::getExpiryDate);
                break;
            default:
                throw new Exception("对应模式不符合");
        }

        return queryWrapper;
    }

    /**
     * @param model 校验出库数据
     * @throws Exception
     */
    private void verificationOutbound(InventoryOutboundVo model) throws Exception {
        if (null == model.getStockId()) {
            throw new Exception("stockId 为空");
        }
        if (ObjectUtils.allNull(model.getItem())) {
            throw new Exception("item 为空");

        }
        if (BooleanUtil.isTrue(model.getItem().getBatchManagement()) && StringUtils.isBlank(model.getBatchNo())) {
            throw new Exception("item.batchManagement == true 时 batchNo 为空");
        }

        if (QtyIsZeroConfig.isOpen) {
            if (model.getQty() == null) {
                throw new Exception("操作数量不能为空");
            }
        } else if (model.getQty() == null || BigDecimal.ZERO.equals(model.getQty())) {
            throw new Exception("操作数量不能为空或零");
        }
        if (!BooleanUtil.isTrue(model.getSupportNegative()) && model.getQty().compareTo(BigDecimal.ZERO) < 0) {
            throw new Exception("操作数量不能为负数");
        }
    }

    /**
     * @param inventoryOutboundVo 主表  拼接sql
     * @return
     */
    private LambdaQueryWrapper<Inventory> queryWrapperInventoryOutboundSql(InventoryOutboundVo inventoryOutboundVo) throws Exception {
        //过滤 条件 null也过滤
        LambdaQueryWrapper<Inventory> queryWrapper = new LambdaQueryWrapper<>();
        if (inventoryOutboundVo.getStockId() == null) {
            queryWrapper.isNull(Inventory::getStockId);
        } else {
            queryWrapper.eq(Inventory::getStockId, inventoryOutboundVo.getStockId());
        }
        if (inventoryOutboundVo.getProjectId() == null) {
            queryWrapper.isNull(Inventory::getProjectId);
        } else {
            queryWrapper.eq(Inventory::getProjectId, inventoryOutboundVo.getProjectId());
        }
        if (inventoryOutboundVo.getItem().getId() == null) {
            queryWrapper.isNull(Inventory::getItemId);
        } else {
            queryWrapper.eq(Inventory::getItemId, inventoryOutboundVo.getItem().getId());
        }
        if (StringUtils.isNotBlank(inventoryOutboundVo.getBatchNo())) {
            queryWrapper.eq(Inventory::getBatchNo, inventoryOutboundVo.getBatchNo());
        } else {
            queryWrapper.isNull(Inventory::getBatchNo);
        }
        switch (inventoryOutboundVo.getModel().getValue()) {
            case PatternVo.FIFO:
                queryWrapper.orderByAsc(Inventory::getExpiryDate);
                break;
            case PatternVo.LIFO:
                queryWrapper.orderByDesc(Inventory::getExpiryDate);
                break;
            case PatternVo.ExpiryEarlier:
                //近有效期先出"不新鲜" ？？
                queryWrapper.orderByAsc(Inventory::getExpiryDate);
                break;
            case PatternVo.ExpiryLater:
                queryWrapper.orderByDesc(Inventory::getExpiryDate);
                break;
            default:
                throw new Exception("对应模式不符合");
        }

        return queryWrapper;
    }


    /**
     * 单个入库（无事务）
     *
     * @param inventoryStorageVo 入库
     * @return
     * @throws Exception
     */
    @Override
    public synchronized InventoryListReturnVo storageItem(InventoryStorageVo inventoryStorageVo) throws Exception {
        getDocumentType(inventoryStorageVo.getDocumentType());
        InventoryListReturnVo inventoryListReturnVo = new InventoryListReturnVo();
        if (inventoryStorageVo.getQty().compareTo(BigDecimal.ZERO) == 0) {
            return inventoryListReturnVo;
        }
        List<BinIdsVo> binIdsVos = new ArrayList<>();
        Inventory inventory = CollUtil.getFirst(inventoryMapper.selectByStorageOne(inventoryStorageVo));
        //验证仓库,产品,负库存等
        verificationStorage(inventoryStorageVo, inventory == null ? null : inventory.getAuxQty());
        //仓位处理 (仓库内码:仓位id)
        if (null != inventoryStorageVo.getBinIds()) {
            binIdsVos = inventoryStorageVo.getBinIds().entrySet().stream().map(c -> new BinIdsVo(c.getKey(), c.getValue())).collect(Collectors.toList());
            long sum = binIdsVos.stream().mapToLong(BinIdsVo::getQty).sum();
            if (QtyIsZeroConfig.isOpen) {
                // = 0
                if (inventoryStorageVo.getQty().compareTo(BigDecimal.ZERO) == 0) {
                    return new InventoryListReturnVo();
                }
                // 仓库数量 =! 仓位数量
                if (inventoryStorageVo.getQty().longValue() != sum) {
                    throw new Exception("bindIds 为非空时，所有入位数量合计不等于qty");
                }
                // 仓库数量 =! 仓位数量
            } else if (sum <= 0 || inventoryStorageVo.getQty().longValue() != sum) {
                throw new Exception("bindIds 为非空时，所有入位数量大于0并且合计不等于qty");
            }
        }
        //如果开启库龄配置 添加一条 不处理库位存放
        if (StockAgeConfig.isOpen) {
            storageAgeInsert(inventoryStorageVo, inventoryListReturnVo, binIdsVos);
        }
        //添加总表 + 仓位表
        if (null == inventory) {
            //直接copy 添加 处理
            if (getIsOpenNegativeInventory(inventoryStorageVo.getStockId())) {
                //如果入库数量是正数 不校验  负数 校验
                if (inventoryStorageVo.getQty().compareTo(BigDecimal.ZERO) < 0) {
                    throw new Exception("入库负数不允许");
                }
            }
            inventoryListReturnVo = storageInsert(inventoryStorageVo, inventoryListReturnVo, binIdsVos);
        }
        //更新总表  + 仓位表
        else {
            inventoryListReturnVo = storageUpdate(inventoryStorageVo, inventoryListReturnVo, inventory, binIdsVos);
        }
        return inventoryListReturnVo;
    }

    /**
     * 如果启用 批次库存  直接添加
     *
     * @param inventoryStorageVo
     */
    private InventoryListReturnVo storageAgeInsert(InventoryStorageVo inventoryStorageVo, InventoryListReturnVo inventoryListReturnVo, List<BinIdsVo> binIdsVos) throws Exception {
        if (inventoryStorageVo.getQty().compareTo(BigDecimal.ZERO) < 0) {
            InventoryOutboundVo model = new InventoryOutboundVo();
            BeanUtils.copyProperties(inventoryStorageVo, model);
            model.setQty(model.getQty().negate());
            model.setModel(PatternEnum.FIFO);
            model.setFrom(inventoryStorageVo.getTo());
            List<InventoryBatchNo> list = inventoryBatchNoMapper.selectByOutboundList(model, model.getModel().getValue());
            if (CollectionUtils.isEmpty(list)) {
                // 是否开启负库存 如果开启
                if (getIsOpenNegativeInventory(inventoryStorageVo.getStockId())) {
                    throw new Exception(getItemIdName(inventoryStorageVo.getItem().getId()) + " 没有查到对应批次库存表数据");
                }
            }
            // 是否开启负库存
            if (getIsOpenNegativeInventory(model.getStockId())) {
                verificationOutboundInventoryBatchNo(model, list);
            }
            return outboundUpdateBatchNo(model, list, binIdsVos);

        }
        InventoryBatchNo insertInventory = new InventoryBatchNo();
        BeanUtils.copyProperties(inventoryStorageVo, insertInventory);
        if (StringUtils.isBlank(inventoryStorageVo.getBatchNo())) {
            insertInventory.setBatchNo(null);
        }
        insertInventory.setStockAgeBatchNo(inventoryStorageVo.getBatchNo());
        InventoryVariation inventoryVariation = new InventoryVariation();
        BeanUtils.copyProperties(inventoryStorageVo, inventoryVariation);
        inventoryVariation.setChangeType("In");
        inventoryVariation.setFromType(inventoryStorageVo.getTo().getValue());
        inventoryVariation.setItemId(inventoryStorageVo.getItem().getId());
        inventoryVariation.setOperateTime(new Date());
        switch (inventoryStorageVo.getTo().getValue()) {
            case TargetTypeVo.Normal:
                inventoryVariation.setStockQty(inventoryStorageVo.getQty());
                inventoryVariation.setChangeStockQty(inventoryStorageVo.getQty());
                insertInventory.setStockQty(inventoryStorageVo.getQty());
                insertInventory.setItemId(inventoryStorageVo.getItem().getId());
                inventoryBatchNoMapper.insert(insertInventory);
                break;
            case TargetTypeVo.Lock:
                inventoryVariation.setLockQty(inventoryStorageVo.getQty());
                inventoryVariation.setStockQty(inventoryStorageVo.getQty());
                inventoryVariation.setChangeLockQty(inventoryStorageVo.getQty());
                insertInventory.setStockQty(inventoryStorageVo.getQty());
                insertInventory.setLockQty(inventoryStorageVo.getQty());
                insertInventory.setItemId(inventoryStorageVo.getItem().getId());
                inventoryBatchNoMapper.insert(insertInventory);
                break;
            case TargetTypeVo.Display:
                inventoryVariation.setDisplayQty(inventoryStorageVo.getQty());
                inventoryVariation.setStockQty(inventoryStorageVo.getQty());
                inventoryVariation.setChangeDisplayQty(inventoryStorageVo.getQty());
                insertInventory.setStockQty(inventoryStorageVo.getQty());
                insertInventory.setDisplayQty(inventoryStorageVo.getQty());
                insertInventory.setItemId(inventoryStorageVo.getItem().getId());
                inventoryBatchNoMapper.insert(insertInventory);
                break;
            case TargetTypeVo.Defect:
                //新增没有正常困粗 不存在展示 直接 抛异常
//                if(getIsOpenNegativeInventory(inventoryStorageVo.getStockId())){
//                    throw new Exception(getItemIdName(inventoryStorageVo.getItem().getId())+"入库数量大于库存数量-锁库数据-残次数量");
//                }else {
                inventoryVariation.setDefectQty(inventoryStorageVo.getQty());
                inventoryVariation.setChangeDefectQty(inventoryStorageVo.getQty());
                insertInventory.setStockQty(inventoryStorageVo.getQty());
                insertInventory.setDefectQty(inventoryStorageVo.getQty());
                insertInventory.setItemId(inventoryStorageVo.getItem().getId());
                inventoryBatchNoMapper.insert(insertInventory);
                break;
//                 }
//                inventoryVariation.setDefectQty(new BigDecimal(inventoryStorageVo.getQty()));
//                insertInventory.setStockQty(new BigDecimal(inventoryStorageVo.getQty()));
//                insertInventory.setItemId(inventoryStorageVo.getItem().getId());
//                this.save(insertInventory);
//                break;
            case TargetTypeVo.Way:
                inventoryVariation.setWayQty(inventoryStorageVo.getQty());
                inventoryVariation.setChangeWayQty(inventoryStorageVo.getQty());
                insertInventory.setWayQty(inventoryStorageVo.getQty());
                insertInventory.setItemId(inventoryStorageVo.getItem().getId());
                inventoryBatchNoMapper.insert(insertInventory);
                break;
            case TargetTypeVo.Storage:
                inventoryVariation.setStorageQty(inventoryStorageVo.getQty());
                inventoryVariation.setChangeStorageQty(inventoryStorageVo.getQty());
                insertInventory.setStorageQty(inventoryStorageVo.getQty());
                insertInventory.setItemId(inventoryStorageVo.getItem().getId());
                inventoryBatchNoMapper.insert(insertInventory);
                break;
            case TargetTypeVo.RejectLock:
                inventoryVariation.setRejectLockQty(inventoryStorageVo.getQty());
                inventoryVariation.setChangeStorageQty(inventoryStorageVo.getQty());
                insertInventory.setRejectLockQty(inventoryStorageVo.getQty());
                insertInventory.setItemId(inventoryStorageVo.getItem().getId());
                inventoryBatchNoMapper.insert(insertInventory);
                break;
            case TargetTypeVo.RejectWay:
                inventoryVariation.setRejectWayQty(inventoryStorageVo.getQty());
                inventoryVariation.setChangeRejectWayQty(inventoryStorageVo.getQty());
                insertInventory.setRejectWayQty(inventoryStorageVo.getQty());
                insertInventory.setItemId(inventoryStorageVo.getItem().getId());
                inventoryBatchNoMapper.insert(insertInventory);
                break;
            case TargetTypeVo.Inspected:
                inventoryVariation.setInspectedQty(inventoryStorageVo.getQty());
                inventoryVariation.setChangeInspectedQty(inventoryStorageVo.getQty());
                insertInventory.setInspectedQty(inventoryStorageVo.getQty());
                insertInventory.setItemId(inventoryStorageVo.getItem().getId());
                inventoryBatchNoMapper.insert(insertInventory);
                break;
            case TargetTypeVo.Picking:
                inventoryVariation.setPickingQty(inventoryStorageVo.getQty());
                inventoryVariation.setChangePickingQty(inventoryStorageVo.getQty());
                insertInventory.setPickingQty(inventoryStorageVo.getQty());
                insertInventory.setItemId(inventoryStorageVo.getItem().getId());
                inventoryBatchNoMapper.insert(insertInventory);
                break;
            default:
                throw new Exception("入库目标类型不正确");
        }
        List<Long> addIds = new ArrayList<>();
        addIds.add(insertInventory.getId());
        inventoryListReturnVo.setAddIds(addIds);

        List<Long> variationIds = new ArrayList<>();
        variationIds.add(inventoryVariation.getId());
        inventoryListReturnVo.setVariationIds(variationIds);
        return inventoryListReturnVo;
    }

    private static BigDecimal orZero(BigDecimal decimal) {
        if (decimal == null) {
            return BigDecimal.ZERO;
        }
        return decimal;
    }

    /**
     * @param inventoryStorageVo    传入的参数
     * @param inventoryListReturnVo 返回的参数
     * @param binIdsVos             binids 集合
     * @return
     * @throws Exception
     */
    private InventoryListReturnVo storageInsert(InventoryStorageVo inventoryStorageVo, InventoryListReturnVo inventoryListReturnVo, List<BinIdsVo> binIdsVos) throws Exception {
        Inventory insertInventory = new Inventory();
        BeanUtils.copyProperties(inventoryStorageVo, insertInventory);
        if (StringUtils.isBlank(inventoryStorageVo.getBatchNo())) {
            insertInventory.setBatchNo(null);
        }
        InventoryVariation inventoryVariation = new InventoryVariation();

        BeanUtils.copyProperties(inventoryStorageVo, inventoryVariation);
        inventoryVariation.setChangeType("In");
        inventoryVariation.setFromType(inventoryStorageVo.getTo().getValue());
        inventoryVariation.setItemId(inventoryStorageVo.getItem().getId());
        inventoryVariation.setOperateTime(new Date());
        //存入对应字段
        switch (inventoryStorageVo.getTo().getValue()) {
            case TargetTypeVo.Normal:
                inventoryVariation.setStockQty(inventoryStorageVo.getQty());
                inventoryVariation.setChangeStockQty(inventoryStorageVo.getQty());
                insertInventory.setStockQty(inventoryStorageVo.getQty());
                insertInventory.setItemId(inventoryStorageVo.getItem().getId());
                this.save(insertInventory);
                break;
            case TargetTypeVo.Lock:
                inventoryVariation.setLockQty(inventoryStorageVo.getQty());
                inventoryVariation.setStockQty(inventoryStorageVo.getQty());
                inventoryVariation.setChangeLockQty(inventoryStorageVo.getQty());
                insertInventory.setStockQty(inventoryStorageVo.getQty());
                insertInventory.setLockQty(inventoryStorageVo.getQty());
                insertInventory.setItemId(inventoryStorageVo.getItem().getId());
                this.save(insertInventory);
                break;
            case TargetTypeVo.Display:
                inventoryVariation.setDisplayQty(inventoryStorageVo.getQty());
                inventoryVariation.setStockQty(inventoryStorageVo.getQty());
                inventoryVariation.setChangeDisplayQty(inventoryStorageVo.getQty());
                insertInventory.setStockQty(inventoryStorageVo.getQty());
                insertInventory.setItemId(inventoryStorageVo.getItem().getId());
                this.save(insertInventory);
                break;
            case TargetTypeVo.Defect:
                //新增没有正常库存  不存在展示 直接 抛异常 如果开启负数库存允许
//                if(getIsOpenNegativeInventory(inventoryStorageVo.getStockId())){
//                    throw new Exception(getItemIdName(inventoryStorageVo.getItem().getId())+"入库数量大于库存数量-锁库数据-残次数量");
//                }else {
                inventoryVariation.setDefectQty(inventoryStorageVo.getQty());
                inventoryVariation.setChangeDefectQty(inventoryStorageVo.getQty());
                insertInventory.setStockQty(inventoryStorageVo.getQty());
                insertInventory.setDefectQty(inventoryStorageVo.getQty());
                insertInventory.setItemId(inventoryStorageVo.getItem().getId());
                this.save(insertInventory);
                break;
            //        }
            case TargetTypeVo.Way:
                inventoryVariation.setWayQty(inventoryStorageVo.getQty());
                inventoryVariation.setChangeWayQty(inventoryStorageVo.getQty());
                insertInventory.setWayQty(inventoryStorageVo.getQty());
                insertInventory.setItemId(inventoryStorageVo.getItem().getId());
                this.save(insertInventory);
                break;
            case TargetTypeVo.Storage:
                inventoryVariation.setStorageQty(inventoryStorageVo.getQty());
                inventoryVariation.setChangeStorageQty(inventoryStorageVo.getQty());
                insertInventory.setStorageQty(inventoryStorageVo.getQty());
                insertInventory.setItemId(inventoryStorageVo.getItem().getId());
                this.save(insertInventory);
                break;
            case TargetTypeVo.RejectLock:
                inventoryVariation.setRejectLockQty(inventoryStorageVo.getQty());
                inventoryVariation.setChangeRejectLockQty(inventoryStorageVo.getQty());
                insertInventory.setRejectLockQty(inventoryStorageVo.getQty());
                insertInventory.setItemId(inventoryStorageVo.getItem().getId());
                this.save(insertInventory);
                break;
            case TargetTypeVo.RejectWay:
                inventoryVariation.setRejectWayQty(inventoryStorageVo.getQty());
                inventoryVariation.setChangeRejectWayQty(inventoryStorageVo.getQty());
                insertInventory.setRejectWayQty(inventoryStorageVo.getQty());
                insertInventory.setItemId(inventoryStorageVo.getItem().getId());
                this.save(insertInventory);
                break;
            case TargetTypeVo.Inspected:
                inventoryVariation.setInspectedQty(inventoryStorageVo.getQty());
                inventoryVariation.setChangeInspectedQty(inventoryStorageVo.getQty());
                insertInventory.setInspectedQty(inventoryStorageVo.getQty());
                insertInventory.setItemId(inventoryStorageVo.getItem().getId());
                this.save(insertInventory);
                break;
            case TargetTypeVo.Picking:
                inventoryVariation.setPickingQty(inventoryStorageVo.getQty());
                inventoryVariation.setChangePickingQty(inventoryStorageVo.getQty());
                insertInventory.setPickingQty(inventoryStorageVo.getQty());
                insertInventory.setItemId(inventoryStorageVo.getItem().getId());
                this.save(insertInventory);
                break;
            default:
                throw new Exception("入库目标类型不正确");
        }
        List<Long> addIds = new ArrayList<>();
        addIds.add(insertInventory.getId());
        inventoryListReturnVo.setAddIds(addIds);
        //处理完 主表添加 库存变动 和村村存放置

        inventoryVariationMapper.insert(inventoryVariation);

        //仓位处理(只支持:正常,锁定库存,在途库存)
        if (binIdsVos.size() != 0) {
            for (BinIdsVo binIdsVo : binIdsVos) {
                //没有库位根据维度查询:   1  可用暂存  2 次品暂存 3 可用 4 次品
                if (ObjectUtils.isEmpty(binIdsVo.getBinId())) {
                    if (inventoryStorageVo.getTo().getValue().equals(TargetTypeVo.Defect)) {
                        binIdsVo.setBinId(getSearchByWarehouseBin(inventoryStorageVo.getStockId(), inventoryStorageVo.getShopId(), inventoryStorageVo.getFnSku(), inventoryStorageVo.getItem().getId(), 2));
                    } else {
                        binIdsVo.setBinId(getSearchByWarehouseBin(inventoryStorageVo.getStockId(), inventoryStorageVo.getShopId(), inventoryStorageVo.getFnSku(), inventoryStorageVo.getItem().getId(), 1));
                    }
                }
                InventoryPlacementVariation inventoryPlacementVariation = new InventoryPlacementVariation();
                BeanUtils.copyProperties(inventoryStorageVo, inventoryPlacementVariation);
                inventoryPlacementVariation.setChangeType("In");
                inventoryPlacementVariation.setFromType(inventoryStorageVo.getFromBinIdsType().getValue());
                inventoryPlacementVariation.setItemId(inventoryStorageVo.getItem().getId());
                inventoryPlacementVariation.setOperateTime(new Date());
                inventoryPlacementVariation.setBinId(binIdsVo.getBinId());
                List<InventoryPlacement> inventoryPlacementList = inventoryPlacementMapper.selectStorageByWhereOne(inventoryStorageVo, binIdsVo.getBinId());
                InventoryPlacement inventoryPlacement = new InventoryPlacement();
                if (CollectionUtils.isNotEmpty(inventoryPlacementList)) {
                    inventoryPlacement = inventoryPlacementList.get(0);
                } else {
                    inventoryPlacement = null;
                }
                if (inventoryPlacement != null) {
                    LambdaUpdateChainWrapper<InventoryPlacement> inventoryPlacementUpdateChainWrapper = new LambdaUpdateChainWrapper<>(inventoryPlacementMapper);
                    switch (inventoryStorageVo.getFromBinIdsType().getValue()) {
                        case TargetTypeVo.Normal:
                            inventoryPlacementVariation.setStockQty(orZero(inventoryPlacement.getStockQty()).add(new BigDecimal(binIdsVo.getQty())));
                            inventoryPlacementVariation.setChangeStockQty(new BigDecimal(binIdsVo.getQty()));
                            // InventoryPlacement updateInventoryPlacement=new InventoryPlacement();
                            if (inventoryPlacement.getStockQty() != null) {
                                inventoryPlacementUpdateChainWrapper.set(InventoryPlacement::getStockQty, inventoryPlacement.getStockQty().add(new BigDecimal(binIdsVo.getQty())));
                                //updateInventoryPlacement.setStockQty(inventoryPlacement.getStockQty().add(new BigDecimal(binIdsVo.getQty())));
                            } else {
                                inventoryPlacementUpdateChainWrapper.set(InventoryPlacement::getStockQty, new BigDecimal(binIdsVo.getQty()));
                                // updateInventoryPlacement.setStockQty(new BigDecimal(binIdsVo.getQty()));
                            }
                            inventoryPlacementUpdateChainWrapper.eq(InventoryPlacement::getId, inventoryPlacement.getId());
                            inventoryPlacementUpdateChainWrapper.eq(InventoryPlacement::getVersion, inventoryPlacement.getVersion());
                            inventoryPlacementUpdateChainWrapper.set(InventoryPlacement::getVersion, inventoryPlacement.getVersion() + 1);
                            if (!inventoryPlacementUpdateChainWrapper.update()) {
                                throw new Exception("数据版本错误，更新失败");
                            }
                            break;
                        case TargetTypeVo.Lock:
                            inventoryPlacementVariation.setLockQty(orZero(inventoryPlacement.getLockQty()).add(new BigDecimal(binIdsVo.getQty())));
                            inventoryPlacementVariation.setChangeLockQty(new BigDecimal(binIdsVo.getQty()));
                            if (inventoryPlacement.getLockQty() != null) {
                                inventoryPlacementUpdateChainWrapper.set(InventoryPlacement::getLockQty, inventoryPlacement.getLockQty().add(new BigDecimal(binIdsVo.getQty())));
                                //updateInventoryPlacement.setStockQty(inventoryPlacement.getStockQty().add(new BigDecimal(binIdsVo.getQty())));
                            } else {
                                inventoryPlacementUpdateChainWrapper.set(InventoryPlacement::getLockQty, new BigDecimal(binIdsVo.getQty()));
                                // updateInventoryPlacement.setStockQty(new BigDecimal(binIdsVo.getQty()));
                            }
                            inventoryPlacementUpdateChainWrapper.eq(InventoryPlacement::getId, inventoryPlacement.getId());
                            inventoryPlacementUpdateChainWrapper.eq(InventoryPlacement::getVersion, inventoryPlacement.getVersion());
                            inventoryPlacementUpdateChainWrapper.set(InventoryPlacement::getVersion, inventoryPlacement.getVersion() + 1);
                            if (!inventoryPlacementUpdateChainWrapper.update()) {
                                throw new Exception("数据版本错误，更新失败");
                            }
                            break;
                        case TargetTypeVo.Way:
                            inventoryPlacementVariation.setWayQty(orZero(inventoryPlacement.getWayQty()).add(new BigDecimal(binIdsVo.getQty())));
                            inventoryPlacementVariation.setChangeWayQty(new BigDecimal(binIdsVo.getQty()));
                            if (inventoryPlacement.getWayQty() != null) {
                                inventoryPlacementUpdateChainWrapper.set(InventoryPlacement::getWayQty, inventoryPlacement.getWayQty().add(new BigDecimal(binIdsVo.getQty())));
                                //updateInventoryPlacement.setStockQty(inventoryPlacement.getStockQty().add(new BigDecimal(binIdsVo.getQty())));
                            } else {
                                inventoryPlacementUpdateChainWrapper.set(InventoryPlacement::getWayQty, new BigDecimal(binIdsVo.getQty()));
                                // updateInventoryPlacement.setStockQty(new BigDecimal(binIdsVo.getQty()));
                            }
                            inventoryPlacementUpdateChainWrapper.eq(InventoryPlacement::getId, inventoryPlacement.getId());
                            inventoryPlacementUpdateChainWrapper.eq(InventoryPlacement::getVersion, inventoryPlacement.getVersion());
                            inventoryPlacementUpdateChainWrapper.set(InventoryPlacement::getVersion, inventoryPlacement.getVersion() + 1);
                            if (!inventoryPlacementUpdateChainWrapper.update()) {
                                throw new Exception("数据版本错误，更新失败");
                            }
                            break;
                        default:
                            throw new Exception("入库位目标类型不正确");
                    }
                    inventoryPlacementVariationMapper.insert(inventoryPlacementVariation);
//                    updateInventoryPlacement.setId(inventoryPlacement.getId());
//                    inventoryPlacementMapper.updateById(updateInventoryPlacement);
                } else {
                    InventoryPlacement insertInventoryPlacement = new InventoryPlacement();
                    BeanUtils.copyProperties(inventoryStorageVo, insertInventoryPlacement);
                    insertInventoryPlacement.setBinId(binIdsVo.getBinId());
                    //insertInventoryPlacement.setStockQty(new BigDecimal(binIdsVo.getQty()));
                    insertInventoryPlacement.setAuxId(insertInventory.getAuxId());
                    insertInventoryPlacement.setAuxQty(insertInventory.getAuxQty());
                    insertInventoryPlacement.setItemId(inventoryStorageVo.getItem().getId());
                    if (StringUtils.isBlank(inventoryStorageVo.getBatchNo())) {
                        insertInventoryPlacement.setBatchNo(null);
                    }
                    switch (inventoryStorageVo.getFromBinIdsType().getValue()) {
                        case TargetTypeVo.Normal:
                            inventoryPlacementVariation.setStockQty(new BigDecimal(binIdsVo.getQty()));
                            inventoryPlacementVariation.setChangeStockQty(new BigDecimal(binIdsVo.getQty()));
                            insertInventoryPlacement.setStockQty(new BigDecimal(binIdsVo.getQty()));
                            insertInventoryPlacement.setLockQty(null);
                            insertInventoryPlacement.setWayQty(null);
                            break;
                        case TargetTypeVo.Way:
                            inventoryPlacementVariation.setWayQty(new BigDecimal(binIdsVo.getQty()));
                            inventoryPlacementVariation.setChangeWayQty(new BigDecimal(binIdsVo.getQty()));
                            insertInventoryPlacement.setWayQty(new BigDecimal(binIdsVo.getQty()));
                            insertInventoryPlacement.setStockQty(null);
                            insertInventoryPlacement.setLockQty(null);
                            break;
                        case TargetTypeVo.Lock:
                            inventoryPlacementVariation.setLockQty(new BigDecimal(binIdsVo.getQty()));
                            inventoryPlacementVariation.setChangeLockQty(new BigDecimal(binIdsVo.getQty()));
                            insertInventoryPlacement.setLockQty(new BigDecimal(binIdsVo.getQty()));
                            insertInventoryPlacement.setStockQty(null);
                            insertInventoryPlacement.setWayQty(null);
                            break;
                        default:
                            throw new Exception("入库位目标类型不正确");
                    }
                    inventoryPlacementMapper.insert(insertInventoryPlacement);
                    inventoryPlacementVariationMapper.insert(inventoryPlacementVariation);
                }
            }
        }
        List<Long> variationIds = new ArrayList<>();
        variationIds.add(inventoryVariation.getId());
        inventoryListReturnVo.setVariationIds(variationIds);
        return inventoryListReturnVo;
    }

    private void validStock(Long itemId, BigDecimal stockQty, BigDecimal lockQty, BigDecimal displayQty, BigDecimal defectQty, BigDecimal wayQty, BigDecimal storageQty, BigDecimal rejectLockQty, BigDecimal rgetRejectWayQty, BigDecimal inspectedQty) throws Exception {
        String itemIdName = "";
        if (StringUtils.isNotBlank(MaterialConfig.sql)) {
            try {
                String sql = String.format(MaterialConfig.sql, itemId);
                itemIdName = inventoryMapper.selectMaterial(sql);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        if (stockQty.compareTo(BigDecimal.ZERO) < 0) {
            throw new Exception(itemIdName + " 总库存不能小于 0");
        }
        if (lockQty.compareTo(BigDecimal.ZERO) < 0) {
            throw new Exception(itemIdName + " 锁定库存不能小于 0");
        }
        if (displayQty.compareTo(BigDecimal.ZERO) < 0) {
            throw new Exception(itemIdName + " 展示库存不能小于 0");
        }
        if (defectQty.compareTo(BigDecimal.ZERO) < 0) {
            throw new Exception(itemIdName + " 残次库存不能小于 0");
        }
        if (lockQty.add(displayQty).add(defectQty).compareTo(stockQty) > 0) {
            throw new Exception(itemIdName + " 锁定库存加展示库存加残次库存不能大于总库存");
        }
        if (wayQty.compareTo(BigDecimal.ZERO) < 0) {
            throw new Exception(itemIdName + " 在途库存不能小于 0");
        }
        if (storageQty.compareTo(BigDecimal.ZERO) < 0) {
            throw new Exception(itemIdName + " 暂存库存不能小于 0");
        }
        if (rejectLockQty.compareTo(BigDecimal.ZERO) < 0) {
            throw new Exception(itemIdName + " 次品锁定库存不能小于 0");
        }
        if (rgetRejectWayQty.compareTo(BigDecimal.ZERO) < 0) {
            throw new Exception(itemIdName + " 次品在途库存不能小于 0");
        }
        if (inspectedQty.compareTo(BigDecimal.ZERO) < 0) {
            throw new Exception(itemIdName + " 待检库存不能小于 0");
        }

    }

    /**
     * @param inventoryStorageVo    传入的参数
     * @param inventoryListReturnVo 返回的参数
     * @param inventory             修改的库存实体
     * @param binIdsVos             binids 集合
     * @return
     * @throws Exception
     */
    private InventoryListReturnVo storageUpdate(InventoryStorageVo inventoryStorageVo, InventoryListReturnVo inventoryListReturnVo, Inventory inventory, List<BinIdsVo> binIdsVos) throws Exception {

        LambdaUpdateChainWrapper<Inventory> inventoryUpdateChainWrapper = new LambdaUpdateChainWrapper<>(inventoryMapper);

        inventoryUpdateChainWrapper.eq(Inventory::getId, inventory.getId());
        inventoryUpdateChainWrapper.eq(Inventory::getVersion, inventory.getVersion());
        inventoryUpdateChainWrapper.set(Inventory::getVersion, inventory.getVersion() + 1);

        List<Long> updateIds = new ArrayList<>();
        updateIds.add(inventory.getId());
        inventoryListReturnVo.setUpdateIds(updateIds);

        BigDecimal stockQty = orZero(inventory.getStockQty());
        BigDecimal lockQty = orZero(inventory.getLockQty());
        BigDecimal displayQty = orZero(inventory.getDisplayQty());
        BigDecimal defectQty = orZero(inventory.getDefectQty());
        BigDecimal wayQty = orZero(inventory.getWayQty());
        BigDecimal storageQty = orZero(inventory.getStorageQty());
        BigDecimal rejectLockQty = orZero(inventory.getRejectLockQty());
        BigDecimal rgetRejectWayQty = orZero(inventory.getRejectWayQty());
        BigDecimal inspectedQty = orZero(inventory.getInspectedQty());
        BigDecimal pickingQty = orZero(inventory.getPickingQty());
        // 库存变动
        InventoryVariation inventoryVariation = new InventoryVariation();
        BeanUtils.copyProperties(inventoryStorageVo, inventoryVariation);
        switch (inventoryStorageVo.getTo().getValue()) {
            case TargetTypeVo.Normal:
                stockQty = stockQty.add(inventoryStorageVo.getQty());
                inventoryVariation.setChangeStockQty(inventoryStorageVo.getQty());
                inventoryUpdateChainWrapper.set(Inventory::getStockQty, stockQty);
                break;
            case TargetTypeVo.Lock:
                stockQty = stockQty.add(inventoryStorageVo.getQty());
                lockQty = lockQty.add(inventoryStorageVo.getQty());
                inventoryVariation.setChangeStockQty(inventoryStorageVo.getQty());
                inventoryVariation.setChangeLockQty(inventoryStorageVo.getQty());
                inventoryUpdateChainWrapper.set(Inventory::getStockQty, stockQty);
                inventoryUpdateChainWrapper.set(Inventory::getLockQty, lockQty);
                break;
            case TargetTypeVo.Display:
                stockQty = stockQty.add(inventoryStorageVo.getQty());
                displayQty = displayQty.add(inventoryStorageVo.getQty());
                inventoryVariation.setChangeStockQty(inventoryStorageVo.getQty());
                inventoryVariation.setChangeDisplayQty(inventoryStorageVo.getQty());
                inventoryUpdateChainWrapper.set(Inventory::getStockQty, stockQty);
                inventoryUpdateChainWrapper.set(Inventory::getDisplayQty, displayQty);
                break;
            case TargetTypeVo.Defect:
                stockQty = stockQty.add(inventoryStorageVo.getQty());
                defectQty = defectQty.add(inventoryStorageVo.getQty());
                inventoryVariation.setChangeStockQty(inventoryStorageVo.getQty());
                inventoryVariation.setChangeDefectQty(inventoryStorageVo.getQty());
                inventoryUpdateChainWrapper.set(Inventory::getStockQty, stockQty);
                inventoryUpdateChainWrapper.set(Inventory::getDefectQty, defectQty);
                break;
            case TargetTypeVo.Way:
                wayQty = wayQty.add(inventoryStorageVo.getQty());
                inventoryVariation.setChangeWayQty(inventoryStorageVo.getQty());
                inventoryUpdateChainWrapper.set(Inventory::getWayQty, wayQty);
                break;
            case TargetTypeVo.Storage:
                storageQty = storageQty.add(inventoryStorageVo.getQty());
                inventoryVariation.setChangeStorageQty(inventoryStorageVo.getQty());
                inventoryUpdateChainWrapper.set(Inventory::getStorageQty, storageQty);
                break;
            case TargetTypeVo.RejectLock:
                rejectLockQty = rejectLockQty.add(inventoryStorageVo.getQty());
                inventoryVariation.setChangeRejectLockQty(inventoryStorageVo.getQty());
                inventoryUpdateChainWrapper.set(Inventory::getRejectLockQty, rejectLockQty);
                break;
            case TargetTypeVo.RejectWay:
                rgetRejectWayQty = rgetRejectWayQty.add(inventoryStorageVo.getQty());
                inventoryVariation.setChangeRejectWayQty(inventoryStorageVo.getQty());
                inventoryUpdateChainWrapper.set(Inventory::getRejectWayQty, rgetRejectWayQty);
                break;
            case TargetTypeVo.Inspected:
                inspectedQty = inspectedQty.add(inventoryStorageVo.getQty());
                inventoryVariation.setChangeInspectedQty(inventoryStorageVo.getQty());
                inventoryUpdateChainWrapper.set(Inventory::getInspectedQty, inspectedQty);
                break;
            case TargetTypeVo.Picking:
                pickingQty = pickingQty.add(inventoryStorageVo.getQty());
                inventoryVariation.setChangeInspectedQty(inventoryStorageVo.getQty());
                inventoryUpdateChainWrapper.set(Inventory::getPickingQty, pickingQty);
                break;
            default:
                throw new Exception("入库目标类型不正确");
        }
        if (getIsOpenNegativeInventory(inventoryStorageVo.getStockId())) {
            validStock(inventory.getItemId(), stockQty, lockQty, displayQty, defectQty, wayQty, storageQty, rejectLockQty, rgetRejectWayQty, inspectedQty);
        }

        if (!inventoryUpdateChainWrapper.update()) {
            throw new Exception("数据版本错误，更新失败");
        }

        inventoryVariation.setStockQty(stockQty);
        inventoryVariation.setLockQty(lockQty);
        inventoryVariation.setDisplayQty(displayQty);
        inventoryVariation.setDefectQty(defectQty);
        inventoryVariation.setWayQty(wayQty);
        inventoryVariation.setStorageQty(storageQty);
        inventoryVariation.setRejectLockQty(rejectLockQty);
        inventoryVariation.setRejectWayQty(rgetRejectWayQty);
        inventoryVariation.setInspectedQty(inspectedQty);

        inventoryVariation.setChangeType("In");
        inventoryVariation.setFromType(inventoryStorageVo.getTo().getValue());
        inventoryVariation.setItemId(inventoryStorageVo.getItem().getId());
        inventoryVariation.setOperateTime(new Date());
        inventoryVariationMapper.insert(inventoryVariation);
        if (binIdsVos.size() != 0) {
            for (BinIdsVo binIdsVo : binIdsVos) {
                if (ObjectUtils.isEmpty(binIdsVo.getBinId())) {
                    if (inventoryStorageVo.getTo().getValue().equals(TargetTypeVo.Defect)) {
                        binIdsVo.setBinId(getSearchByWarehouseBin(inventoryStorageVo.getStockId(), inventoryStorageVo.getShopId(), inventoryStorageVo.getFnSku(), inventoryStorageVo.getItem().getId(), 2));
                    } else {
                        binIdsVo.setBinId(getSearchByWarehouseBin(inventoryStorageVo.getStockId(), inventoryStorageVo.getShopId(), inventoryStorageVo.getFnSku(), inventoryStorageVo.getItem().getId(), 1));
                    }
                }
                InventoryPlacementVariation inventoryPlacementVariation = new InventoryPlacementVariation();
                BeanUtils.copyProperties(inventoryStorageVo, inventoryPlacementVariation);
                inventoryPlacementVariation.setChangeType("In");
                inventoryPlacementVariation.setFromType(inventoryStorageVo.getFromBinIdsType().getValue());
                inventoryPlacementVariation.setItemId(inventoryStorageVo.getItem().getId());
                inventoryPlacementVariation.setOperateTime(new Date());
                inventoryPlacementVariation.setBinId(binIdsVo.getBinId());
                List<InventoryPlacement> inventoryPlacementList = inventoryPlacementMapper.selectStorageByWhereOne(inventoryStorageVo, binIdsVo.getBinId());
                InventoryPlacement inventoryPlacement = new InventoryPlacement();
                if (CollectionUtils.isNotEmpty(inventoryPlacementList)) {
                    inventoryPlacement = inventoryPlacementList.get(0);
                } else {
                    inventoryPlacement = null;
                }
                if (inventoryPlacement != null) {
                    LambdaUpdateChainWrapper<InventoryPlacement> inventoryPlacementUpdateChainWrapper = new LambdaUpdateChainWrapper<>(inventoryPlacementMapper);
                    switch (inventoryStorageVo.getFromBinIdsType().getValue()) {
                        case TargetTypeVo.Normal:
                            inventoryPlacementVariation.setStockQty(orZero(inventoryPlacement.getStockQty()).add(new BigDecimal(binIdsVo.getQty())));
                            if (inventoryPlacementVariation.getStockQty().compareTo(BigDecimal.ZERO) < 0) {
                                throw new Exception("库存货位放置表在可用库存不足");
                            }
                            inventoryPlacementVariation.setChangeStockQty(new BigDecimal(binIdsVo.getQty()));
                            if (inventoryPlacement.getStockQty() != null) {
                                inventoryPlacementUpdateChainWrapper.set(InventoryPlacement::getStockQty, inventoryPlacement.getStockQty().add(new BigDecimal(binIdsVo.getQty())));
                            } else {
                                inventoryPlacementUpdateChainWrapper.set(InventoryPlacement::getStockQty, new BigDecimal(binIdsVo.getQty()));
                            }
                            break;
                        case TargetTypeVo.Lock:
                            inventoryPlacementVariation.setLockQty(orZero(inventoryPlacement.getLockQty()).add(new BigDecimal(binIdsVo.getQty())));
                            if (inventoryPlacementVariation.getLockQty().compareTo(BigDecimal.ZERO) < 0) {
                                throw new Exception("库存货位放置表在锁定库存不足");
                            }
                            inventoryPlacementVariation.setChangeLockQty(new BigDecimal(binIdsVo.getQty()));
                            if (inventoryPlacement.getLockQty() != null) {
                                inventoryPlacementUpdateChainWrapper.set(InventoryPlacement::getLockQty, inventoryPlacement.getLockQty().add(new BigDecimal(binIdsVo.getQty())));
                            } else {
                                inventoryPlacementUpdateChainWrapper.set(InventoryPlacement::getLockQty, new BigDecimal(binIdsVo.getQty()));
                            }
                            break;
                        case TargetTypeVo.Way:
                            inventoryPlacementVariation.setWayQty(orZero(inventoryPlacement.getWayQty()).add(new BigDecimal(binIdsVo.getQty())));
                            if (inventoryPlacementVariation.getWayQty().compareTo(BigDecimal.ZERO) < 0) {
                                throw new Exception("库存货位放置表在途库存不足");
                            }
                            inventoryPlacementVariation.setChangeWayQty(new BigDecimal(binIdsVo.getQty()));
                            if (inventoryPlacement.getWayQty() != null) {
                                inventoryPlacementUpdateChainWrapper.set(InventoryPlacement::getWayQty, inventoryPlacement.getWayQty().add(new BigDecimal(binIdsVo.getQty())));
                            } else {
                                inventoryPlacementUpdateChainWrapper.set(InventoryPlacement::getWayQty, new BigDecimal(binIdsVo.getQty()));
                            }
                            break;
                        default:
                            throw new Exception("入库位目标类型不正确");
                    }
                    inventoryPlacementUpdateChainWrapper.eq(InventoryPlacement::getId, inventoryPlacement.getId());
                    inventoryPlacementUpdateChainWrapper.eq(InventoryPlacement::getVersion, inventoryPlacement.getVersion());
                    inventoryPlacementUpdateChainWrapper.set(InventoryPlacement::getVersion, inventoryPlacement.getVersion() + 1);
                    if (!inventoryPlacementUpdateChainWrapper.update()) {
                        throw new Exception("数据版本错误，更新失败");
                    }
                    inventoryPlacementVariationMapper.insert(inventoryPlacementVariation);
//                    updateInventoryPlacement.setId(inventoryPlacement.getId());
//                    inventoryPlacementMapper.updateById(updateInventoryPlacement);
                } else {
                    if (new BigDecimal(binIdsVo.getQty()).compareTo(BigDecimal.ZERO) < 0) {
                        throw new Exception("库存货位放置表库存不足");
                    }
                    InventoryPlacement insertInventoryPlacement = new InventoryPlacement();
                    BeanUtils.copyProperties(inventoryStorageVo, insertInventoryPlacement);
                    insertInventoryPlacement.setBinId(binIdsVo.getBinId());
                    //insertInventoryPlacement.setStockQty(new BigDecimal(binIdsVo.getQty()));
                    insertInventoryPlacement.setAuxId(inventory.getAuxId());
                    insertInventoryPlacement.setAuxQty(inventory.getAuxQty());
                    insertInventoryPlacement.setItemId(inventoryStorageVo.getItem().getId());
                    if (StringUtils.isBlank(inventoryStorageVo.getBatchNo())) {
                        insertInventoryPlacement.setBatchNo(null);
                    }
                    switch (inventoryStorageVo.getFromBinIdsType().getValue()) {
                        case TargetTypeVo.Normal:
                            insertInventoryPlacement.setStockQty(new BigDecimal(binIdsVo.getQty()));
                            insertInventoryPlacement.setLockQty(null);
                            insertInventoryPlacement.setWayQty(null);
                            inventoryPlacementVariation.setStockQty(new BigDecimal(binIdsVo.getQty()));
                            inventoryPlacementVariation.setChangeStockQty(new BigDecimal(binIdsVo.getQty()));
                            break;
                        case TargetTypeVo.Lock:
                            insertInventoryPlacement.setStockQty(null);
                            insertInventoryPlacement.setLockQty(new BigDecimal(binIdsVo.getQty()));
                            insertInventoryPlacement.setWayQty(null);
                            inventoryPlacementVariation.setLockQty(new BigDecimal(binIdsVo.getQty()));
                            inventoryPlacementVariation.setChangeLockQty(new BigDecimal(binIdsVo.getQty()));
                            break;
                        case TargetTypeVo.Way:
                            insertInventoryPlacement.setStockQty(null);
                            insertInventoryPlacement.setLockQty(null);
                            insertInventoryPlacement.setWayQty(new BigDecimal(binIdsVo.getQty()));
                            inventoryPlacementVariation.setWayQty(new BigDecimal(binIdsVo.getQty()));
                            inventoryPlacementVariation.setChangeWayQty(new BigDecimal(binIdsVo.getQty()));
                            break;
                        default:
                            throw new Exception("入库位目标类型不正确");
                    }
                    inventoryPlacementMapper.insert(insertInventoryPlacement);
                    inventoryPlacementVariationMapper.insert(inventoryPlacementVariation);
                }
            }
        }
        List<Long> variationIds = new ArrayList<>();
        variationIds.add(inventoryVariation.getId());
        inventoryListReturnVo.setVariationIds(variationIds);
        return inventoryListReturnVo;
    }

    /**
     * @param inventoryStorageVo 库存货位放置表  拼接sql
     * @return
     */
    private LambdaQueryWrapper<InventoryPlacement> queryWrapperInventoryPlacementSql(InventoryStorageVo inventoryStorageVo, Integer binId) {
        //过滤 条件 null也过滤
        LambdaQueryWrapper<InventoryPlacement> queryWrapper = new LambdaQueryWrapper<>();
        if (binId == null) {
            queryWrapper.isNull(InventoryPlacement::getBinId);
        } else {
            queryWrapper.eq(InventoryPlacement::getBinId, binId);
        }
        if (inventoryStorageVo.getStockId() == null) {
            queryWrapper.isNull(InventoryPlacement::getStockId);
        } else {
            queryWrapper.eq(InventoryPlacement::getStockId, inventoryStorageVo.getStockId());
        }
        if (inventoryStorageVo.getProjectId() == null) {
            queryWrapper.isNull(InventoryPlacement::getProjectId);
        } else {
            queryWrapper.eq(InventoryPlacement::getProjectId, inventoryStorageVo.getProjectId());
        }
        if (inventoryStorageVo.getItem().getId() == null) {
            queryWrapper.isNull(InventoryPlacement::getItemId);
        } else {
            queryWrapper.eq(InventoryPlacement::getItemId, inventoryStorageVo.getItem().getId());
        }
        if (StringUtils.isNotBlank(inventoryStorageVo.getBatchNo())) {
            queryWrapper.eq(InventoryPlacement::getBatchNo, inventoryStorageVo.getBatchNo());
        } else {
            queryWrapper.isNull(InventoryPlacement::getBatchNo);
        }
        if (inventoryStorageVo.getExpiryDate() == null) {
            queryWrapper.isNull(InventoryPlacement::getExpiryDate);
        } else {
            queryWrapper.eq(InventoryPlacement::getExpiryDate, inventoryStorageVo.getExpiryDate());
        }
        return queryWrapper;
    }

    /**
     * @param inventoryStorageVo 主表  拼接sql
     * @return
     */
    private LambdaQueryWrapper<Inventory> queryWrapperInventorySql(InventoryStorageVo inventoryStorageVo) throws Exception {
        //过滤 条件 null也过滤
        LambdaQueryWrapper<Inventory> queryWrapper = new LambdaQueryWrapper<>();
        if (inventoryStorageVo.getStockId() == null) {
            throw new Exception("stockId 为空");
        } else {
            queryWrapper.eq(Inventory::getStockId, inventoryStorageVo.getStockId());
        }
        if (inventoryStorageVo.getProjectId() == null) {
            queryWrapper.isNull(Inventory::getProjectId);
        } else {
            queryWrapper.eq(Inventory::getProjectId, inventoryStorageVo.getProjectId());
        }
        if (inventoryStorageVo.getItem().getId() == null) {
            queryWrapper.isNull(Inventory::getItemId);
        } else {
            queryWrapper.eq(Inventory::getItemId, inventoryStorageVo.getItem().getId());
        }
        if (StringUtils.isNotBlank(inventoryStorageVo.getBatchNo())) {
            queryWrapper.eq(Inventory::getBatchNo, inventoryStorageVo.getBatchNo());
        } else {
            queryWrapper.isNull(Inventory::getBatchNo);
        }
        if (inventoryStorageVo.getExpiryDate() == null) {
            queryWrapper.isNull(Inventory::getExpiryDate);
        } else {
            queryWrapper.eq(Inventory::getExpiryDate, inventoryStorageVo.getExpiryDate());
        }
        return queryWrapper;
    }

    /**
     * @param inventoryListVo 校验
     * @throws Exception
     */
    private void verificationStorage(InventoryStorageVo inventoryListVo, BigDecimal auxQty) throws Exception {
        Assert.isTrue(ObjUtil.isAllNotEmpty(inventoryListVo.getStockId(), inventoryListVo.getItem()), "仓库内码 或 库存物料接口为空！");
        //预留
        if (BooleanUtil.isTrue(inventoryListVo.getItem().getBatchManagement()) && StrUtil.isBlank(inventoryListVo.getBatchNo())) {
            throw new Exception("item.batchManagement == true 时 batchNo 为空");
        }

        //预留
        if (BooleanUtil.isTrue(inventoryListVo.getItem().getShelfLifeManagement()) && ObjUtil.isEmpty(inventoryListVo.getShelfLife()) && ObjUtil.isEmpty(inventoryListVo.getProductionDate()) && ObjUtil.isEmpty(inventoryListVo.getExpiryDate())
        ) {
            throw new Exception("item.shelfLifeManagement == true 时 shelfLife, productionDate 或 expiryDate 为空");
        }
        //预留
        if (BooleanUtil.isTrue(inventoryListVo.getItem().getAuxiliaryMetering())) {
            if (ObjUtil.isEmpty(inventoryListVo.getItem().getAuxId()) || ObjUtil.isEmpty(auxQty)) {
                //主表的字段？？？
                throw new Exception("auxId 或 auxQty 为空");
            }
        }
        if (QtyIsZeroConfig.isOpen) {
            if (ObjUtil.isEmpty(inventoryListVo.getQty())) {
                throw new Exception("操作数量不能为空");
            }
        } else if (ObjUtil.isEmpty(inventoryListVo.getQty()) || NumberUtil.equals(BigDecimal.ZERO, inventoryListVo.getQty())) {
            throw new Exception("操作数量不能为空或零");
        }
        if (!BooleanUtil.isTrue(inventoryListVo.getSupportNegative()) && NumberUtil.isLess(inventoryListVo.getQty(), BigDecimal.ZERO)) {
            throw new Exception("操作数量不能为负数");
        }
    }

    static class ChangeNum {
        private BigDecimal initValue;
        private BigDecimal newValue;

        public ChangeNum(BigDecimal initValue) {
            this.initValue = initValue;
        }

        public void resetInitValue(BigDecimal initValue) {
            this.initValue = initValue;
        }

        public BigDecimal getInitValue() {
            return initValue;
        }

        public BigDecimal getNewValue() {
            return newValue;
        }

        public void setNewValue(BigDecimal newValue) {
            this.newValue = newValue;
        }

        public BigDecimal getValue() {
            if (newValue != null) {
                return newValue;
            }
            if (initValue != null) {
                return initValue;
            }
            return BigDecimal.ZERO;
        }

        public BigDecimal add(BigDecimal value) {
            newValue = orZero(getValue()).add(value);
            return newValue;
        }

        public BigDecimal subtract(BigDecimal value) {
            newValue = orZero(getValue()).subtract(value);
            return newValue;
        }

        public BigDecimal getChange() {
            if (orZero(initValue).equals(orZero(newValue))) {
                return null;
            }
            return orZero(newValue).subtract(orZero(initValue));
        }

        public BigDecimal getNotNullValue() {
            return orZero(getValue());
        }

        public boolean isNegative() {
            if (newValue != null) {
                return newValue.compareTo(BigDecimal.ZERO) < 0;
            }
            if (initValue != null) {
                return initValue.compareTo(BigDecimal.ZERO) < 0;
            }
            return false;
        }
    }

    private String getItemIdName(Long itemId) {
        String itemIdName = "";
        if (StringUtils.isNotBlank(MaterialConfig.sql)) {
            try {
                String sql = String.format(MaterialConfig.sql, itemId);
                itemIdName = inventoryMapper.selectMaterial(sql);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        return itemIdName;
    }

    /**
     * 根据仓库  是否允许负库存 true 允许 false 不允许
     *
     * @param
     * @return
     */
    private Boolean getIsOpenNegativeInventory(Long stockId) {
        if (StringUtils.isNotBlank(InventoryConfig.sql)) {
            try {
                String sql = String.format(InventoryConfig.sql, stockId);
                Integer i = inventoryMapper.selectNegativeInventoryCount(sql);
                if (i > 0) {
                    return false;
                }
            } catch (Exception e) {

            }
        }
        return true;
    }

    /**
     * 单据类型 校验
     *
     * @param
     * @return
     */
    private void getDocumentType(String documentType) throws Exception {
        if (DocumentTypecConfig.isOpen) {
            if (ObjectUtils.isEmpty(documentType)) {
                throw new Exception("单据类型不能为空");
            }
        }

    }

    /**
     * 根据当前时间生成分配批次号
     *
     * @return
     */
    private static String createBatchNo() {
        // 返回分配批次
        return StrUtil.concat(true, DateUtil.format(DateUtil.date(), DatePattern.PURE_DATETIME_PATTERN), "-", RandomUtil.randomNumbers(6));
    }

    /**
     * @param StockId 仓库
     * @param shopId  店铺
     * @param fnSku   fnsku
     * @param itemId  商品id
     * @param type    类型  1  可用暂存  2 次品暂存 3 可用 4 次品
     * @return
     * @throws Exception
     */
    public Long getSearchByWarehouseBin(Long StockId, String shopId, String fnSku, Long itemId, Integer type) throws Exception {
        WarehouseBinRulesSearchParamPo searchParamPo = new WarehouseBinRulesSearchParamPo();
        searchParamPo.setProductId(itemId);
        if (!ObjectUtils.isEmpty(shopId)) {
            searchParamPo.setShopId(Long.valueOf(shopId));
        }
        searchParamPo.setWarehouseId(StockId);
        searchParamPo.setFnSku(fnSku);
        searchParamPo.setType(type);
        WarehouseBinRulesItemVo warehouseBinRulesItemVo = warehouseBinRulesService.searchNew(searchParamPo);
        return warehouseBinRulesItemVo.getId();
    }

}
